写点什么

【高并发】ScheduledThreadPoolExecutor 与 Timer 的区别和简单示例

作者:冰河
  • 2022-10-12
    四川
  • 本文字数:2403 字

    阅读完需:约 1 分钟

【高并发】ScheduledThreadPoolExecutor与Timer的区别和简单示例

JDK 1.5 开始提供 ScheduledThreadPoolExecutor 类,ScheduledThreadPoolExecutor 类继承 ThreadPoolExecutor 类重用线程池实现了任务的周期性调度功能。在 JDK 1.5 之前,实现任务的周期性调度主要使用的是 Timer 类和 TimerTask 类。本文,就简单介绍下 ScheduledThreadPoolExecutor 类与 Timer 类的区别,ScheduledThreadPoolExecutor 类相比于 Timer 类来说,究竟有哪些优势,以及二者分别实现任务调度的简单示例。

二者的区别

线程角度

  • Timer 是单线程模式,如果某个 TimerTask 任务的执行时间比较久,会影响到其他任务的调度执行。

  • ScheduledThreadPoolExecutor 是多线程模式,并且重用线程池,某个 ScheduledFutureTask 任务执行的时间比较久,不会影响到其他任务的调度执行。

系统时间敏感度

  • Timer 调度是基于操作系统的绝对时间的,对操作系统的时间敏感,一旦操作系统的时间改变,则 Timer 的调度不再精确。

  • ScheduledThreadPoolExecutor 调度是基于相对时间的,不受操作系统时间改变的影响。

是否捕获异常

  • Timer 不会捕获 TimerTask 抛出的异常,加上 Timer 又是单线程的。一旦某个调度任务出现异常,则整个线程就会终止,其他需要调度的任务也不再执行。

  • ScheduledThreadPoolExecutor 基于线程池来实现调度功能,某个任务抛出异常后,其他任务仍能正常执行。

任务是否具备优先级

  • Timer 中执行的 TimerTask 任务整体上没有优先级的概念,只是按照系统的绝对时间来执行任务。

  • ScheduledThreadPoolExecutor 中执行的 ScheduledFutureTask 类实现了 java.lang.Comparable 接口和 java.util.concurrent.Delayed 接口,这也就说明了 ScheduledFutureTask 类中实现了两个非常重要的方法,一个是 java.lang.Comparable 接口的 compareTo 方法,一个是 java.util.concurrent.Delayed 接口的 getDelay 方法。在 ScheduledFutureTask 类中 compareTo 方法方法实现了任务的比较,距离下次执行的时间间隔短的任务会排在前面,也就是说,距离下次执行的时间间隔短的任务的优先级比较高。而 getDelay 方法则能够返回距离下次任务执行的时间间隔。

是否支持对任务排序

  • Timer 不支持对任务的排序。

  • ScheduledThreadPoolExecutor 类中定义了一个静态内部类 DelayedWorkQueue,DelayedWorkQueue 类本质上是一个有序队列,为需要调度的每个任务按照距离下次执行时间间隔的大小来排序

能否获取返回的结果

  • Timer 中执行的 TimerTask 类只是实现了 java.lang.Runnable 接口,无法从 TimerTask 中获取返回的结果。

  • ScheduledThreadPoolExecutor 中执行的 ScheduledFutureTask 类继承了 FutureTask 类,能够通过 Future 来获取返回的结果。


通过以上对 ScheduledThreadPoolExecutor 类和 Timer 类的分析对比,相信在 JDK 1.5 之后,就没有使用 Timer 来实现定时任务调度的必要了。

二者简单的示例

这里,给出使用 Timer 和 ScheduledThreadPoolExecutor 实现定时调度的简单示例,为了简便,我这里就直接使用匿名内部类的形式来提交任务。

Timer 类简单示例

源代码示例如下所示。


package io.binghe.concurrent.lab09;
import java.util.Timer;import java.util.TimerTask;
/** * @author binghe * @version 1.0.0 * @description 测试Timer */public class TimerTest {
public static void main(String[] args) throws InterruptedException { Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println("测试Timer类"); } }, 1000, 1000); Thread.sleep(10000); timer.cancel(); }}
复制代码


运行结果如下所示。


测试Timer类测试Timer类测试Timer类测试Timer类测试Timer类测试Timer类测试Timer类测试Timer类测试Timer类测试Timer类
复制代码

ScheduledThreadPoolExecutor 类简单示例

源代码示例如下所示。


package io.binghe.concurrent.lab09;
import java.util.concurrent.*;
/** * @author binghe * @version 1.0.0 * @description 测试ScheduledThreadPoolExecutor */public class ScheduledThreadPoolExecutorTest { public static void main(String[] args) throws InterruptedException { ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("测试测试ScheduledThreadPoolExecutor"); } }, 1, 1, TimeUnit.SECONDS);
//主线程休眠10秒 Thread.sleep(10000);
System.out.println("正在关闭线程池..."); // 关闭线程池 scheduledExecutorService.shutdown(); boolean isClosed; // 等待线程池终止 do { isClosed = scheduledExecutorService.awaitTermination(1, TimeUnit.DAYS); System.out.println("正在等待线程池中的任务执行完成"); } while(!isClosed);
System.out.println("所有线程执行结束,线程池关闭"); }}
复制代码


运行结果如下所示。


测试测试ScheduledThreadPoolExecutor测试测试ScheduledThreadPoolExecutor测试测试ScheduledThreadPoolExecutor测试测试ScheduledThreadPoolExecutor测试测试ScheduledThreadPoolExecutor测试测试ScheduledThreadPoolExecutor测试测试ScheduledThreadPoolExecutor测试测试ScheduledThreadPoolExecutor测试测试ScheduledThreadPoolExecutor正在关闭线程池...测试测试ScheduledThreadPoolExecutor正在等待线程池中的任务执行完成所有线程执行结束,线程池关闭
复制代码


注意:关于 Timer 和 ScheduledThreadPoolExecutor 还有其他的使用方法,这里,我就简单列出以上两个使用示例,更多的使用方法大家可以自行实现。

发布于: 2022-10-12阅读数: 14
用户头像

冰河

关注

公众号:冰河技术,专注写硬核技术专栏。 2020-05-29 加入

互联网资深技术专家,《深入理解高并发编程:核心原理与案例实战》《深入理解分布式事务:原理与实战》《海量数据处理与大数据技术实战》《MySQL技术大全》作者,mykit-data框架作者。【冰河技术】作者。

评论

发布
暂无评论
【高并发】ScheduledThreadPoolExecutor与Timer的区别和简单示例_并发编程_冰河_InfoQ写作社区