Java并发包中ScheduledThreadPoolExcutor原理探究
Java并发包中ScheduledThreadPoolExcutor原理探究
1. 介绍
ScheduledFutureTask内部还有一个变量period用来表示任务的类型,任务类型如下:
period = 0, 说明当前任务是一次性的,执行完毕后就退出了。
period为负数,说明当前任务为fixed-delay任务,是固定延迟的定时可重复执行任务。
period为正数,说明当前任务为fixed-rate任务,是固定频率的定时可重复执行任务。
ScheduledThreadPoolExecutor的一个构造函数如下,由该构造函数可知线程池队列是DelayedWorkQueue。
//使用改造后的Delayqueue
public ScheduledPoolExecutor(int corePoolSize){
//调用父类ThreadPoolExcutor的构造函数
super(corePoolSize,Integer.MAX_VALUE,0,TimeUnit.NANOSECONDS,
new DelayedWorkedQueue());
}
public ThreadPoolExcutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue){
this(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,
Executors.defaultThreadFactory(),defaultHandler);
}
2. 原理剖析
三个重要函数:schedule(Runnable command,long delay,TimeUnit unit)
scheduleWithFixedDelay(Runnable command, long initialDelay,long delay,TimeUnit unit)
scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)
-
schedule(Runnable command,long delay, TimeUnit unit)方法
该方法的作用是提交一个延迟执行的任务,任务从提交时间算起延迟单位为unit的delay时间后开始执行。提交的任务不是周期性任务,任务只会执行一次,代码如下。
public ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit){ //(1)参数校验 if(command == null || unit == null) throw new NullPointerException(); //(2)任务转换 RunnableScheduleFuture<?> t = decorateTask(command,new ScheduledFutureTask<Void> (command,null,triggerTime(delay,unit))); //(3)添加任务到延迟队列 delayedExecute(t); return t; }ScheduledFutureTask的构造函数如下。
ScheduledFutureTask(Runnable r, V result, long ns){ //调用父类FutureTask的构造函数 super(r, result); this.time = ns; this.period = 0; //period为0,说明为一次性任务 this.sequenceNumber = sequencer.getAndIncrement(); }ScheduledFutureTask的run方法
public void run(){ //是否只执行一次 boolean periodic = isPeriodic(); //取消任务 if(!canRunInCurrentRunState(periodic)) cancel(false); //只执行一次,调用schedule方法的时候 else if(!periodic) ScheduledFutureTask.super.run(); //定时执行 else if(ScheduledFutureTasks.super.runAndReset()){ //设置time = time + period setNextRunTime(); //重新加入该任务到delay队列 reExecutePeriodic(outerTask); } } -
scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)方法
该方法的作用是,当任务执行完毕后,让其延迟固定时间后再次运行(fixed-delay任务)。其中initialDelay表示提交任务后延迟多少时间开始执行任务command,delay表示当任务执行完毕后延长多少时间后再次运行command任务,unit是initialDelay和delay的时间单位。任务会一直重复运行直到任务运行中抛出了异常,被取消了,或者关闭了线程池。
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long inititalDelay, long delay,TimeUnit unit){ //参数校验 if(command == null || unit == null) throw new NullPointerException(); if(dealy <= 0) throw new IllegalArgumentException(); //任务转换,注意这里是period = -delay < 0 ScheduledFutureTask<Void> sft = new ScheduledFutureTask<Void>(command,null, triggerTime(initialDelay,unit),unit.toNanos(-delay)); RunnablScheduledFuture<Void> t = decorateTask(command,sft); sft.outerTask = t; //添加任务到队列 delayedExecute(t); return t; } -
scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)方法
该方法相对起始时间点以固定频率调用指定的任务(fixed-rate任务)。当把任务提交到线程池并延迟initialDelay时间(时间单位为unit)后开始执行任务command。然后从initialDelay+period时间点再次执行,而后在initialDelay+2 * period时间点再次执行,循环往复,直到抛出异常或者调用了任务的cancel方法取消了任务,或者关闭了线程池。
相对于fixed-delay任务来说,fixed-rate方式执行规则为,时间为initdelday +n*period时启动任务,但是如果当前任务还没有执行完,下一次要执行任务的时间到了,则不会并发执行,下次要执行的任务会延迟执行,要等到当前任务执行完毕后再执行。
3. 总结
本章讲解了ScheduledThreadPoolExecutor的实现原理,如图9-2所示,其内部使用DelayQueue来存放具体任务。任务分为三种,其中一次性执行任务执行完毕就结束了,fixed-delay任务保证同一个任务在多次执行之间间隔固定时间,fixed-rate任务保证按照固定的频率执行。任务类型使用period的值来区分。

浙公网安备 33010602011771号