目录
1、ScheduledThreadPoolExecutor 结构:
1.2、ScheduledThreadPoolExecutor 构造器
2.3、ScheduledFutureTask 相关方法介绍
根据Timer类可知,得有优先级任务队列queue,延迟任务task,执行方法。
ScheduledThreadPoolExecutor 也是这样,不过其优先级阻塞队列是 DelayedWorkQueue
, 定期任务是ScheduledFutureTask,执行是ThreadPoolExecutor。
1、ScheduledThreadPoolExecutor 结构:
public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor //继承了线程池,那么初始化,方法调用等可以直接复用 implements ScheduledExecutorService { //实现了 ScheduledExecutorService 接口,接口定义了 schedule 、 scheduleAtFixedRate 、 scheduleWithFixedDelay 三类方法,见名知意,分别为定时任务一次性任务,固定速率 和 固定间隔,返回值都为 ScheduledFuture类
1.1、ScheduledFuture类
extends Delayed, Future<V>类,可以拿去任务执行返回值 Future接口的get方法,是否结束等等,以及接口 Delayed 的 getDelay(TimeUnit unit) 获取任务的 延迟时间方法。
1.2、ScheduledThreadPoolExecutor 构造器
一共由有4个构造器,选参数多的说明。
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory, handler);
}
//super 调用父类ThreadPoolExecutor中的构造器如下
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
corePoolSize: 线程池中线程的数量。
ThreadFactory: 工厂用何种方式创建一个线程。
RejectedExecutionHandler: 由于达到线程边界和队列满了,那么要阻止执行使用的处理方式。
具体应用实现以下代码供参考:
return new ScheduledThreadPoolExecutor(10,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
new ThreadPoolExecutor.CallerRunsPolicy())
{
@Override
protected void afterExecute(Runnable r, Throwable t)
{
super.afterExecute(r, t);
Threads.printException(r, t);
}
};
2、 ScheduledFutureTask 结构
ScheduledFutureTask是 ScheduledThreadPoolExecutor的私有内部类,其相当于Timer类中的TimerTask,用于定义任务相关。其结构如下图所示:
private class ScheduledFutureTask<V>
extends FutureTask<V> implements RunnableScheduledFuture<V> {}
其还是需要覆盖 FutureTask 的run() 方法,implements RunnableScheduledFuture 接口,需要实现其isPeriodic()方法。下面一个一个解释,先看字段
2.1、ScheduledFutureTask字段
/** 断开FIFO连接的序列号 */
private final long sequenceNumber;
/** 任务何时执行,单位是纳秒 */
private long time;
/**
* 0是一次性(非重复)任务,正值固定速率,负值固定间隔。
*/
private final long period;
/** 实际运行的任务,定期任务需要重新加入队列,指向当前任务对象 */
RunnableScheduledFuture<V> outerTask = this;
/**
* 索引到阻塞队列中,以支持更快的cancel()操作。
*/
int heapIndex;
其中主要关注运行时间time,时间间隔period,当前任务outerTask;
2.2、ScheduledFutureTask 构造器
/**
* 创建一个一次性任务,此时period为0,time时间单位为纳秒
*/
ScheduledFutureTask(Runnable r, V result, long ns) {
super(r, result);
this.time = ns;
this.period = 0;
this.sequenceNumber = sequencer.getAndIncrement();
}
/**
* 创建一个定期执行任务,super(r,result)也是将Runnable和返回值结合,拼成一个callable
*/
ScheduledFutureTask(Runnable r, V result, long ns, long period) {
super(r, result);
this.time = ns;
this.period = period;
this.sequenceNumber = sequencer.getAndIncrement();
}
2.3、ScheduledFutureTask 相关方法介绍
2.3.1、isPeriodic()
/**
* 判断一个任务是否是定期任务,还是一次性任务,通过period字段判断
*/
public boolean isPeriodic() {
return period != 0;
}
2.3.2、run(),重头
/**
* 重写了FutureTask的run()方法,任务执行主体
*/
public void run() {
boolean periodic = isPeriodic();
if (!canRunInCurrentRunState(periodic))//判断任务是否能在当前线程池状态下运行
cancel(false);
else if (!periodic) //不是定期任务,是一次性任务,那么执行
ScheduledFutureTask.super.run();
else if (ScheduledFutureTask.super.runAndReset()) { //此时条件一定是定期任务,runAndSet()会执行run()方法,确保任务任务执行不止一次
setNextRunTime();//设置下一次执行任务时间
reExecutePeriodic(outerTask); //将任务重新插入队列
}
}
}
private void setNextRunTime() {
long p = period;
if (p > 0)
time += p;
else
time = triggerTime(-p);
}
void reExecutePeriodic(RunnableScheduledFuture<?> task) {
if (canRunInCurrentRunState(true)) { //当前状态可以运行,加入到队列中
super.getQueue().add(task);
if (!canRunInCurrentRunState(true) && remove(task))
task.cancel(false);
else
ensurePrestart(); //确保能启动,线程池相关
}
}
3、DelayedWorkQueue 阻塞队列
//只能往队列添加RunnableScheduledFutures类,其implements Runnbale接口
static class DelayedWorkQueue extends AbstractQueue<Runnable>
implements BlockingQueue<Runnable> {}
就是往优先级阻塞队列中添加,删除,获取,消费 RunnableScheduledFutures对象,需要搭配 ThreadPoolExecutor 一起使用。ThreadPoolExecutor的 getTask()方法会调用 DelayedWorkQueue 中的 take()方法,消费一个阻塞队列中的最先执行对象。感觉有点复杂,不想写。
public RunnableScheduledFuture<?> take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
RunnableScheduledFuture<?> first = queue[0];
if (first == null)
available.await();
else {
long delay = first.getDelay(NANOSECONDS);
if (delay <= 0)
return finishPoll(first);
first = null; // don't retain ref while waiting
if (leader != null)
available.await();
else {
Thread thisThread = Thread.currentThread();
leader = thisThread;
try {
available.awaitNanos(delay);
} finally {
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
if (leader == null && queue[0] != null)
available.signal();
lock.unlock();
}
}
4、执行实现流程
通过创建一个ScheduledThreadPoolExecutor对象,此时阻塞队列也初始化了。然后调用其对应方法,以ScheduledThreadPoolExecutor 对象的 schedule()方法为例,需要传参为 一个Runnable任务,延迟时间执行,时间单位,此时为一次性任务,和scheduleAtFixedRate() 、scheduleWithFixedDelay() 相差不多。
创建一个 ScheduledFutureTask 任务,通过decorateTask 修饰为 RunnableScheduledFuture 接口类,然后调用 delayedExecute()方法,将延迟执行任务加入阻塞队列。等待ThreadPoolExecutor执行getTask方法。因为初始化对象ScheduledThreadPoolExecutor时,实际上是创建ThreadPoolExecutor 对象,其字段keepAliveTime为0,直接调用getTask()方法了,然后走DelayedWorkQueue阻塞队列的take()消费一个队列中的对象。
public ScheduledFuture<?> schedule(Runnable command,
long delay,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
RunnableScheduledFuture<?> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null,
triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
private void delayedExecute(RunnableScheduledFuture<?> task) {
if (isShutdown())
reject(task);
else {
//加入阻塞队列,等待执行
super.getQueue().add(task);
if (isShutdown() &&
!canRunInCurrentRunState(task.isPeriodic()) &&
remove(task))
task.cancel(false);
else
ensurePrestart();
}
}