代码的整体逻辑为:
- 判断当前任务的state是否等于NEW , 如果不为NEW则说明任务或者已经执行过 , 或者已经被取消 , 直接返回;
- 如果状态为NEW则接着会通过unsafe类把任务执行线程引用CAS的保存在runner字段中 , 如果保存失败 , 则直接返回;
- 执行任务;如果任务执行发生异常 , 则调用setException()方法保存异常信息 。
protected boolean runAndReset() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return false; boolean ran = false; int s = state; try { Callable<V> c = callable; if (c != null && s == NEW) { try { c.call(); // don't set result ran = true; } catch (Throwable ex) { setException(ex); } } } finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } return ran && s == NEW;}FutureTask类的runAndReset方法与run方法的逻辑基本相同 , 只是runAndReset方法会重置当前任务的执行状态 。ScheduledThreadPoolExecutor类的reExecutePeriodic方法reExecutePeriodic重复执行任务方法 , 源代码如下所示:
void reExecutePeriodic(RunnableScheduledFuture<?> task) { //线程池当前状态下能够执行任务 if (canRunInCurrentRunState(true)) { //与ThreadPoolExecutor不同 , 这里直接把任务加入延迟队列 super.getQueue().add(task);//使用用的DelayedWorkQueue //线程池当前状态下不能执行任务 , 并且成功移除任务 if (!canRunInCurrentRunState(true) && remove(task)) //取消任务 task.cancel(false); else //这里是增加一个worker线程 , 避免提交的任务没有worker去执行 //原因就是该类没有像ThreadPoolExecutor一样 , woker满了才放入队列 ensurePrestart(); }}总体来说reExecutePeriodic方法的逻辑比较简单 , 需要注意的是:调用reExecutePeriodic方法的时候已经执行过一次任务 , 所以 , 并不会触发线程池的拒绝策略;传入reExecutePeriodic方法的任务一定是周期性的任务 。DelayedWorkQueueScheduledThreadPoolExecutor之所以要自己实现阻塞的工作队列 , 是因为 ScheduleThreadPoolExecutor 要求的工作队列有些特殊 。
DelayedWorkQueue是一个基于堆的数据结构 , 类似于DelayQueue和PriorityQueue 。在执行定时任务的时候 , 每个任务的执行时间都不同 , 所以DelayedWorkQueue的工作就是按照执行时间的升序来排列 , 执行时间距离当前时间越近的任务在队列的前面(注意:这里的顺序并不是绝对的 , 堆中的排序只保证了子节点的下次执行时间要比父节点的下次执行时间要大 , 而叶子节点之间并不一定是顺序的) 。
堆结构如下图:

文章插图
可见 , DelayedWorkQueue是一个基于最小堆结构的队列 。堆结构可以使用数组表示 , 可以转换成如下的数组:

文章插图
在这种结构中 , 可以发现有如下特性: 假设“第一个元素” 在数组中的索引为 0 的话 , 则父结点和子结点的位置关系如下:
- 索引为 的左孩子的索引是 (2∗i+1);
- 索引为 的右孩子的索引是 (2∗i+2);
推荐阅读
- 富春山居图是中国十大传名画之一这幅画的作者是 富春山居图是中国十大传世名画之一这幅画的作者是什么
- 古代寒门科举之路 没有科举之前都怎么当官的
- 班盆之美可比之班章,大滇号701批六星贺开
- 张仪得五寸退二寸之谋 张仪三寸不烂之舌纵横六国
- 英雄无用武之地的意思解释 形容英雄无用武之地的词语
- 绿茶之采花毛尖,采花毛尖价格预测
- 武则天在位多少年怎么退位的 武则天退位之后还活了多久
- |当了领导之后才明白的三个道理
- 胎儿男女双顶径对照表
- 康熙用人之术 康熙的用人之道
