【JUC源码解析】ScheduledThreadPoolExecutor
简介
它是一个线程池执行器(ThreadPoolExecutor),在给定的延迟(delay)后执行。在多线程或者对灵活性有要求的环境下,要优于java.util.Timer。
提交的任务在执行之前支持取消,默认情况下,在延迟到来之前,不会自动从队列中删除,但可以设置,使其立刻从队列中移除。
有两种模式,固定频率(scheduleAtFixedRate)和固定延迟(scheduleWithFixedDelay),不管哪种模式,同一个任务不会被叠加执行,即便是不同的线程执行同一个任务。
继承ThreadPoolExecutor,维护一个固定大小的线程池和一个无界延迟队列(delay queue)。
ScheduledFutureTask,用来描述要执行的任务,DelayedWorkQueue,则是装在这些任务的delay queue.
固定频率
一个任务,从第一次开始执行的时间点开始,每隔一定的时间执行一次,如果执行的时间大于间隔时间,则要等这次执行结束,再执行下一次。

如上图所示,蓝色表示任务执行,白色表示间隔时间。
固定延迟
一个任务,每一次执行结束之后,延迟一定的时间,执行下一次。

如上图所示,蓝色表示任务执行,白色表示间隔时间。
源码分析
属性
     private volatile boolean continueExistingPeriodicTasksAfterShutdown; // shut down之后,是否取消period任务
     private volatile boolean executeExistingDelayedTasksAfterShutdown = true; // shut down之后,是否取消non-period任务
     private volatile boolean removeOnCancel = false; // cancel后,是否从队列里移除此任务
     private static final AtomicLong sequencer = new AtomicLong(); // 给任务编号
ScheduledFutureTask
属性
         private final long sequenceNumber; // 序列编号
         private long time; // 执行时间
         private final long period; // 周期,正值:固定频率;负值:固定延迟;0:不重复执行
         RunnableScheduledFuture<V> outerTask = this; // 实际任务
         int heapIndex; // 堆索引
构造方法
         ScheduledFutureTask(Runnable r, V result, long ns) {
             super(r, result);
             this.time = ns;
             this.period = 0; // 不重复执行
             this.sequenceNumber = sequencer.getAndIncrement();
         }
         ScheduledFutureTask(Runnable r, V result, long ns, long period) {
             super(r, result);
             this.time = ns;
             this.period = period;
             this.sequenceNumber = sequencer.getAndIncrement();
         }
         ScheduledFutureTask(Callable<V> callable, long ns) {
             super(callable);
             this.time = ns;
             this.period = 0;
             this.sequenceNumber = sequencer.getAndIncrement();
         }
关键方法
getDelay(TimeUnit)
         public long getDelay(TimeUnit unit) {
             return unit.convert(time - now(), NANOSECONDS);
         }
compareTo(Delayed other)
         public int compareTo(Delayed other) { // 根据延迟比较元素,在延迟队列中,延迟越小越靠前,延迟最小的在队首,最先出队被执行
             if (other == this)
                 return 0;
             if (other instanceof ScheduledFutureTask) {
                 ScheduledFutureTask<?> x = (ScheduledFutureTask<?>) other;
                 long diff = time - x.time;
                 if (diff < 0)
                     return -1;
                 else if (diff > 0)
                     return 1;
                 else if (sequenceNumber < x.sequenceNumber)
                     return -1;
                 else
                     return 1;
             }
             long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
             return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
         }
setNextRunTime()
         private void setNextRunTime() { // 设置下一次执行时间
             long p = period;
             if (p > 0) // 固定频率,从第一次时间点,每次加period
                 time += p;
             else
                 time = triggerTime(-p); // 固定延迟,每次执行结束后,加period作为下一次执行时间
         }
cancel(boolean mayInterruptIfRunning)
         public boolean cancel(boolean mayInterruptIfRunning) { // 取消任务
             boolean cancelled = super.cancel(mayInterruptIfRunning);
             if (cancelled && removeOnCancel && heapIndex >= 0)
                 remove(this);
             return cancelled;
         }
run()
         public void run() { // 执行任务
             boolean periodic = isPeriodic();
             if (!canRunInCurrentRunState(periodic))
                 cancel(false);
             else if (!periodic)
                 ScheduledFutureTask.super.run(); // 单次执行
             else if (ScheduledFutureTask.super.runAndReset()) { // 周期执行,runAndReset
                 setNextRunTime(); // 设置下次执行时间
                 reExecutePeriodic(outerTask); // 重新加入队列
             }
         }
构造方法
     public ScheduledThreadPoolExecutor(int corePoolSize) {
         super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
     }
     public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
         super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory);
     }
     public ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) {
         super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), handler);
     }
     public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory,
             RejectedExecutionHandler handler) {
         super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory, handler);
     }
关键方法
scheduleAtFixedRate
     public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { // 固定频率
         if (command == null || unit == null)
             throw new NullPointerException();
         if (period <= 0)
             throw new IllegalArgumentException();
         ScheduledFutureTask<Void> sft = new ScheduledFutureTask<Void>(command, null, triggerTime(initialDelay, unit),
                 unit.toNanos(period)); // period 大于 0
         RunnableScheduledFuture<Void> t = decorateTask(command, sft);
         sft.outerTask = t;
         delayedExecute(t);
         return t;
     }
scheduleWithFixedDelay
     public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { // 固定延迟
         if (command == null || unit == null)
             throw new NullPointerException();
         if (delay <= 0)
             throw new IllegalArgumentException();
         ScheduledFutureTask<Void> sft = new ScheduledFutureTask<Void>(command, null, triggerTime(initialDelay, unit),
                 unit.toNanos(-delay)); // -delay 小于 0
         RunnableScheduledFuture<Void> t = decorateTask(command, sft);
         sft.outerTask = t;
         delayedExecute(t);
         return t;
     }
delayedExecute(RunnableScheduledFuture<?> task)
     private void delayedExecute(RunnableScheduledFuture<?> task) {
         if (isShutdown()) // 如果线程池已经shut down,则拒绝任务
             reject(task);
         else {
             super.getQueue().add(task); // 否则,添加任务到延迟队列
             if (isShutdown() && !canRunInCurrentRunState(task.isPeriodic()) && remove(task))
                 task.cancel(false); // 根据run-after-shutdown参数,决定是否取任务
             else
                 ensurePrestart(); // 保证线程启动
         }
     }
reExecutePeriodic(RunnableScheduledFuture<?> task)
     void reExecutePeriodic(RunnableScheduledFuture<?> task) { // 周期性任务重新入队,策略同delayedExecute
         if (canRunInCurrentRunState(true)) {
             super.getQueue().add(task);
             if (!canRunInCurrentRunState(true) && remove(task))
                 task.cancel(false);
             else
                 ensurePrestart();
         }
     }
ensurePrestart()
     void ensurePrestart() {
         int wc = workerCountOf(ctl.get());
         if (wc < corePoolSize)
             addWorker(null, true);
         else if (wc == 0)
             addWorker(null, false);
     }
该方法在ThreadPoolExecutor类,保证线程池中至少有一个活动线程。
triggerTime()
     long triggerTime(long delay) { // 返回延迟动作的触发时间
         return now() + ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
     }
     private long overflowFree(long delay) { // 处理溢出情况
         Delayed head = (Delayed) super.getQueue().peek();
         if (head != null) {
             long headDelay = head.getDelay(NANOSECONDS);
             if (headDelay < 0 && (delay - headDelay < 0))
                 delay = Long.MAX_VALUE + headDelay;
         }
         return delay;
     }
DelayedWorkQueue
属性
private static final int INITIAL_CAPACITY = 16; // 初始容量
private RunnableScheduledFuture<?>[] queue = new RunnableScheduledFuture<?>[INITIAL_CAPACITY]; // 堆,充当优先级队列
private final ReentrantLock lock = new ReentrantLock(); // 可重入锁
private int size = 0;
private Thread leader = null; // 领导者线程
private final Condition available = lock.newCondition(); // 条件队列
关键方法
以下这些方法的解释可参考前两篇文章,【JUC源码解析】DelayQueue和【JUC源码解析】PriorityBlockingQueue
siftUp
         private void siftUp(int k, RunnableScheduledFuture<?> key) { // 向上调整,同
             while (k > 0) {
                 int parent = (k - 1) >>> 1;
                 RunnableScheduledFuture<?> e = queue[parent];
                 if (key.compareTo(e) >= 0)
                     break;
                 queue[k] = e;
                 setIndex(e, k);
                 k = parent;
             }
             queue[k] = key;
             setIndex(key, k);
         }
siftDown
         private void siftDown(int k, RunnableScheduledFuture<?> key) { // 向下调整
             int half = size >>> 1;
             while (k < half) {
                 int child = (k << 1) + 1;
                 RunnableScheduledFuture<?> c = queue[child];
                 int right = child + 1;
                 if (right < size && c.compareTo(queue[right]) > 0)
                     c = queue[child = right];
                 if (key.compareTo(c) <= 0)
                     break;
                 queue[k] = c;
                 setIndex(c, k);
                 k = child;
             }
             queue[k] = key;
             setIndex(key, k);
         }
grow
         private void grow() { // 扩容
             int oldCapacity = queue.length;
             int newCapacity = oldCapacity + (oldCapacity >> 1); // grow 50%
             if (newCapacity < 0) // overflow
                 newCapacity = Integer.MAX_VALUE;
             queue = Arrays.copyOf(queue, newCapacity);
         }
offer
         public boolean offer(Runnable x) {
             if (x == null)
                 throw new NullPointerException();
             RunnableScheduledFuture<?> e = (RunnableScheduledFuture<?>) x;
             final ReentrantLock lock = this.lock;
             lock.lock();
             try {
                 int i = size;
                 if (i >= queue.length)
                     grow();
                 size = i + 1;
                 if (i == 0) {
                     queue[0] = e;
                     setIndex(e, 0);
                 } else {
                     siftUp(i, e);
                 }
                 if (queue[0] == e) {
                     leader = null;
                     available.signal();
                 }
             } finally {
                 lock.unlock();
             }
             return true;
         }
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();
             }
         }
行文至此结束。
尊重他人的劳动,转载请注明出处:http://www.cnblogs.com/aniao/p/aniao_stpe.html
【JUC源码解析】ScheduledThreadPoolExecutor的更多相关文章
- 【JUC源码解析】SynchronousQueue
		简介 SynchronousQueue是一种特殊的阻塞队列,该队列没有容量. [存数据线程]到达队列后,若发现没有[取数据线程]在此等待,则[存数据线程]便入队等待,直到有[取数据线程]来取数据,并释 ... 
- 【JUC源码解析】ForkJoinPool
		简介 ForkJoin 框架,另一种风格的线程池(相比于ThreadPoolExecutor),采用分治算法,工作密取策略,极大地提高了并行性.对于那种大任务分割小任务的场景(分治)尤其有用. 框架图 ... 
- 【JUC源码解析】DelayQueue
		简介 基于优先级队列,以过期时间作为排序的基准,剩余时间最少的元素排在队首.只有过期的元素才能出队,在此之前,线程等待. 源码解析 属性 private final transient Reentra ... 
- 【JUC源码解析】CyclicBarrier
		简介 CyclicBarrier,一个同步器,允许多个线程相互等待,直到达到一个公共屏障点. 概述 CyclicBarrier支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后 ... 
- 【JUC源码解析】ConcurrentLinkedQueue
		简介 ConcurrentLinkedQueue是一个基于链表结点的无界线程安全队列. 概述 队列顺序,为FIFO(first-in-first-out):队首元素,是当前排队时间最长的:队尾元素,当 ... 
- 【JUC源码解析】Exchanger
		简介 Exchanger,并发工具类,用于线程间的数据交换. 使用 两个线程,两个缓冲区,一个线程往一个缓冲区里面填数据,另一个线程从另一个缓冲区里面取数据.当填数据的线程将缓冲区填满时,或者取数据的 ... 
- Jdk1.6 JUC源码解析(12)-ArrayBlockingQueue
		功能简介: ArrayBlockingQueue是一种基于数组实现的有界的阻塞队列.队列中的元素遵循先入先出(FIFO)的规则.新元素插入到队列的尾部,从队列头部取出元素. 和普通队列有所不同,该队列 ... 
- Jdk1.6 JUC源码解析(13)-LinkedBlockingQueue
		功能简介: LinkedBlockingQueue是一种基于单向链表实现的有界的(可选的,不指定默认int最大值)阻塞队列.队列中的元素遵循先入先出 (FIFO)的规则.新元素插入到队列的尾部,从队列 ... 
- Jdk1.6 JUC源码解析(6)-locks-AbstractQueuedSynchronizer
		功能简介: AbstractQueuedSynchronizer(以下简称AQS)是Java并发包提供的一个同步基础机制,是并发包中实现Lock和其他同步机制(如:Semaphore.CountDow ... 
随机推荐
- 关于layui(layer)子页面获取不到父页面jQuery对象的问题。
			如果在使用layui-layer模块过程中,在子页面执行代码: window.parent.$("#id").val() 报错:window.parent.$ is not a f ... 
- Maven实战(八)pom.xml简介
			目录 pom作为项目对象模型.通过xml表示maven项目,使用pom.xml来实现.主要描述了项目:包括配置文件.开发者需要遵循的规则.缺陷管理系统.组织和licenses.项目的url.项目的依赖 ... 
- Ubuntu 64 + IntelliJ IDEA + Genymotion 搭建Android开发环境
			环境搭建所需可至 http://pan.baidu.com/s/1gd1Kf4Z 下载 注: 此处假定 Ubuntu 用户名为 chenfei 开发相关全部存放在 /home/chen ... 
- 浅谈 JSONP
			说起跨域的解决方案,总是会说到 JSONP,但是很多时候都没有仔细去了解过 JSONP,可能是因为现在 JSONP 用的不是很多(多数时候都是配置响应头实现跨域),也可能是因为用 JSONP 的场景一 ... 
- SOJ 4583 动态规划之分组背包
			Description Sidney想去Gandtom家玩.但Sidney家和Gandtom家之间是高低不平.坑坑洼洼的土路.所以他需要用他的背包装几袋稀的泥,在路上铺平一些干的土,使路变成平整的泥土 ... 
- 1898: [Zjoi2005]Swamp 沼泽鳄鱼
			1898: [Zjoi2005]Swamp 沼泽鳄鱼 Time Limit: 5 Sec Memory Limit: 64 MB Submit: 1582 Solved: 870 [Submit][S ... 
- h5py
			解决办法: sudo apt-get install libhdf5-dev sudo apt-get install python-h5py 
- 差异是关键,TI首款隔离式CAN收发器评析
			差异是关键,TI首款隔离式CAN收发器评析 “无论是在日常生活还是媒体报道中, CAN接口对大家来说已经司空见惯了,然而将CAN接口和隔离功能整合在同一产品里,这还是业界头一遭,” ... 
- 原型和原型对象(__proto__和prototype)转
			看了之后我总算对原型继承有了更深刻的理解,做爱分享的姑娘,原文链接:理解Javascript 原型 我(个人)不喜欢的,就是讲原型时上来就拿类做比较的,所以我不会这样讲.不过我的确讲过构造器函数,在这 ... 
- ABAP-DBC录屏
			*&---------------------------------------------------------------------**& ZXXL_MM02_01*& ... 
