持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情
1. ScheduledExecutorService 认识
1.1 介绍
ScheduledExecutorService 是 Java 1.5 版本新增的定时任务接口,基于线程池的方式,每个任务会开启一个新的线程执行,互不影响。
ScheduledExecutorService 存在于 java.util.concurrent
包中,其出现主要是针对使用 Timer 定时器的问题。
如果在定时任务中使用了 Timer ,热情的 IDEA 编译器还为主动提供新方案的使用方法:
// 使用 ScheduledExecutorService代替Timer吧
// Inspection info: 处理定时任务时,Timer 运行多个 TimeTask 时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用 ScheduledExecutorService 则没有这个问题。
1.2 使用
- ScheduledExecutorService 可以使用实现的线程池类 ScheduledThreadPoolExecutor 来创建一个具体的对象。
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
//do something
}
},initialDelay,period, TimeUnit.HOURS);
- 除此之外,juc 包中还封装了 Executors 方法类便于快速创建对象,如果不需要自定义相关参数,可以使用 Executors 来初始化。
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
2. ScheduledExecutorService 结构
2.1 接口定义
ScheduledExecutorService 作为一个接口,其继承了 ExecutorService 接口,并且提供了调度命令来延迟或者周期性的执行线程任务。
public interface ScheduledExecutorService extends ExecutorService {
...
}
-
继承了 ExecutorService 接口,则 ExecutorService 其中定义的方法 ScheduledExecutorService 都可以使用
-
因为 ScheduledExecutorService 是一个接口,因此在创建其对象并调用方法时需要使用其实现类:
-
ScheduledThreadPoolExecutor 类,用于创建 ScheduledExecutorService 类型对象,其也继承了线程池创建类,创建时需要指定核心线程数量
-
DelegatedScheduledExecutorService 类,是 Executors 类的内部类
-
2.1 定义方法
除了继承 ExecutorService 接口的方法外,ScheduledExecutorService 中还提供了另外的四个方法
- 创建一次定时任务,并指定触发延迟时间,任务传入 Runnable 参数
ScheduledFuture<?> schedule(Runnable command,long delay, TimeUnit unit);
- 创建一次定时任务,并指定触发延迟时间,任务传入 Callable 参数,并可以获取返回结果
<V> ScheduledFuture<V> schedule(Callable<V> callable,long delay, TimeUnit unit);
- 创建周期执行定时任务,可以参数设置第一次执行时的延迟时长,以及两次成功执行的时间间隔
ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnitunit);
- 如果程序执行时间超过间隔时间,则会在上次执行结束后立即执行下次
- 创建周期执行任务,指定第一次执行延迟时长,以及上次结束后和下次开始间隔时长
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnitunit);
- 此种情况下,间隔时间是从上次任务执行完成后计算,因此可以保证任务的执行顺序
3. ScheduledExecutorService 使用
3.1 任务创建
ScheduledExecutorService提供的方法中需要的任务是 Runnable
或者 Callable<V>
,而实际上 java.util
中的 TimerTask
类也是实现了 Runnable
接口的。
我们可以直接定义任务类来实现 Runnable
接口,并将任务类作为 ScheduledExecutorService
的参数传递执行。
public class Task implements Runnable {
@Override
public void run() {
System.out.println("任务执行,当前时间:"+ System.currentTimeMillis());
}
}
3.2 使用示例
使用时先创建 ScheduledExecutorService 类型的对象,并执行对象的方法。
// 类中的 main 方法,执行定时任务
public static void main(String[] args){
ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1);
scheduledExecutorService.scheduleAtFixedRate(new DoTaskBySchedule(),2,3, TimeUnit.SECONDS);
}
3.3 不足之处
ScheduledExecutorService 在作为定时任务执行时仍然会存在一定的不足,如:
-
没有可以根据时间指定的执行方法,需要传入延迟时间参数执行
-
指定定时任务时会以上次执行完成为前提,上次没有执行完则不会执行下次任务