任务调度之ScheduledThreadPoolExecutor
1、前言
ScheduledExecutorService在普通执行器接口(ExecutorService)的基础上引入了Future模式,使得可以限时或周期性地调度任务。

ScheduledThreadPoolExecutor其实是继承了ThreadPoolExecutor这个普通线程池,同时实现ScheduledThreadPoolExecutorService接口。ThreadPoolExecutor中提交的任务都是实现了Runnable接口,但是ScheduledThreadPoolExecutor比较特殊,由于要满足任务的延迟/周期调度功能,它会对所有的Runnable任务都进行包装,包装成一个RunnableScheduledFuture任务。

RunnableScheduledFuture是Future模式中的一个接口,在ThreadPoolExecutor中,需要指定一个阻塞队列作为任务队列。ScheduledThreadPoolExecutor中也一样,不过特殊的是,ScheduledThreadPoolExecutor中的任务队列是一种特殊的延时队列(DelayQueue)。ScheduledThreadPoolExecutor在内部定义了DelayQueue的变种——DelayedWorkQueue,它和DelayQueue类似,只不过要求所有入队元素必须实现RunnableScheduledFuture接口。
Delayed接口
// 继承Comparable接口,表示该类对象支持排序
public interface Delayed extends Comparable<Delayed> {
// 返回该对象剩余时延
long getDelay(TimeUnit unit);
}
Delayed接口很简单,继承了Comparable接口,表示对象是可以比较排序的。ScheduledFuture接口
// 仅仅继承了Delayed和Future接口,自身没有任何代码
public interface ScheduledFuture<V> extends Delayed, Future<V> {
}
RunnableScheduledFuture接口
public interface RunnableScheduledFuture<V> extends RunnableFuture<V>, Schedule
// 是否是周期任务,周期任务可被调度运行多次,非周期任务只被运行一次
boolean isPeriodic();
}
ScheduledFutureTask类
回到 schecule 方法中,它创建了一个ScheduledFutureTask的对象,由上面的关系图可知,ScheduledFutureTask直接或者间接实现了很多接口,ScheduledFutureTask实现方法:
构造方法
ScheduledFutureTask(Runnable r, V result, long ns, long period) {
// 调父类FutureTask的构造方法
super(r, result);
// time表示任务下次执行的时间
this.time = ns;
// 周期任务,正数表示按照固定速率,负数表示按照固定时延,0表示不是周期任务
this.period = period;
// 任务的编号
this.sequenceNumber = sequencer.getAndIncrement();
}
Delayed接口的实现
// 实现Delayed接口的getDelay方法,返回任务开始执行的剩余时间
public long getDelay(TimeUnit unit) {
return unit.convert(time - now(), TimeUnit.NANOSECONDS);
}
2、实例
指定时间给发送消息。将消息(包含发送时间)存储在数据库中,然后实现一个定时任务,每隔1秒检查数据库在当前时间有没有需要发送的消息。
public class ScheduledTask {
private static final ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1, Executors.defaultThreadFactory());
private static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args){
// 新建一个固定延迟时间的计划任务
executor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
if (haveMsgAtCurrentTime()) {
System.out.println(df.format(new Date()));
System.out.println("大家注意了,我要发消息了");
}
}
}, 1, 1, TimeUnit.SECONDS);
}
public static boolean haveMsgAtCurrentTime(){
//查询数据库,有没有当前时间需要发送的消息
// 这⾥省略实现,直接返回true
return true;
}
}

浙公网安备 33010602011771号