开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情
前言
本篇文章,我们一起来聊聊 ScheduledThreadPoolExecutor、Timer 类的简单使用和实现细节及区别
- JDK 1.5开始提供ScheduledThreadPoolExecutor类,重用线程池实现了任务的周期性调度功能。
- JDK 1.5之前,实现任务的周期性调度主要使用的是 Timer 类和 TimerTask 类。
区别
先来看看两者的区别
线程角度
- Timer 是单线程模式,如果某个 TimerTask 任务的执行时间比较久,会影响到其他任务的调度执行
- ScheduledThreadPoolExecutor 是多线程模式,并且重用线程池,某个 ScheduledFutureTask 任务执行的时间比较久,不会影响到其他任务的调度执行。
是否捕获异常
- Timer 不会捕获 TimerTask 抛出的异常。又因为加上 Timer 是单线程的,若某个调度任务出现异常,则整个线程就会终止,其他需要调度的任务也不再执行。
- ScheduledThreadPoolExecutor 基于线程池来实现调度功能,某个任务抛出异常后,其他任务仍能正常执行。
任务优先级
- Timer 中执行的 TimerTask 任务无优先级的概念,只是按照系统的绝对时间来执行任务。
- ScheduledThreadPoolExecutor 中执行的 ScheduledFutureTask 类实现了 Comparable 接口(实现了compareTo 方法)和 java.util.concurrent.Delayed 接口(实现了 getDelay 方法)。compareTo方法实现了任务的比较,距离下次执行的时间间隔短的任务的优先级比较高。 getDelay方法则能够返回距离下次任务执行的时间间隔。
是否支持对任务排序
- Timer不支持对任务的排序。
- ScheduledThreadPoolExecutor 类中定义了一个静态内部类 DelayedWorkQueue,它是一个有序队列,为需要调度的每个任务按照距离下次执行时间间隔的大小来排序。
获取任务的返回结果
- Timer 中执行的 TimerTask 类只是实现了 java.lang.Runnable 接口,无法从 TimerTask 中获取返回的结果。
- ScheduledThreadPoolExecutor 中执行的 ScheduledFutureTask 类继承了 FutureTask 类,能够通过 Future 来获取返回的结果。
简单示例
Timer 示例
package com.zhongger.threadLearn;
import java.util.Timer;
import java.util.TimerTask;
/**
* @author zhongmingyi
* @date 2023/2/8 10:29 下午
*/
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("执行Time Task");
}
}, 1000, 1000);
Thread.sleep(10000);
timer.cancel();
}
}
ScheduledThreadPoolExecutor 示例
package com.zhongger.threadLearn;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @author zhongmingyi
* @date 2023/2/8 10:34 下午
*/
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);
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("所有线程执行结束,线程池关闭");
}
}