《java.util.concurrent 包源码阅读》14 线程池系列之ScheduledThreadPoolExecutor 第一部分
ScheduledThreadPoolExecutor是ThreadPoolExecutor的子类,同时实现了ScheduledExecutorService接口。
public class ScheduledThreadPoolExecutor
extends ThreadPoolExecutor
implements ScheduledExecutorService
ScheduledThreadPoolExecutor的功能主要有两点:在固定的时间点执行(也可以认为是延迟执行),重复执行。
和分析ThreadPoolExecutor时一样,首先来看核心方法execute:
public void execute(Runnable command) {
schedule(command, 0, TimeUnit.NANOSECONDS);
}
execute方法调用了另外一个方法schedule,同时我们发现三个submit方法也是同样调用了schedule方法,因为有两种类型的任务:Callable和Runnable,因此schedule也有两个重载方法。
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;
} public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay,
TimeUnit unit) {
if (callable == null || unit == null)
throw new NullPointerException();
RunnableScheduledFuture<V> t = decorateTask(callable,
new ScheduledFutureTask<V>(callable,
triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
两个方法逻辑基本一致,都是把任务包装成RunnableScheduledFuture对象,然后调用delayedExecute来实现延迟执行。任务包装类继承自ThreadPoolExecutor的包装类RunnableFuture,同时实现ScheduledFuture接口使包装类具有了延迟执行和重复执行这些功能以匹配ScheduledThreadPoolExecutor。
因此首先来看ScheduledFutureTask,以下是ScheduledFutureTask专有的几个变量:
private class ScheduledFutureTask<V>
extends FutureTask<V> implements RunnableScheduledFuture<V> { /** 针对线程池所有任务的序列号 */
private final long sequenceNumber; /** 距离任务开始执行的时间,纳秒为单位 */
private long time; /**
* 重复执行任务的间隔,即每隔多少时间执行一次任务
*/
private final long period; /** 重复执行任务和排队时用这个类型的对象, */
RunnableScheduledFuture<V> outerTask = this; /**
* 在延迟队列的索引,这样取消任务时使用索引会加快查找速度
*/
int heapIndex;
来看核心方法run:
public void run() {
boolean periodic = isPeriodic();
// 检测是否可以运行任务,这里涉及到另外两个变量:continueExistingPeriodicTasksAfterShutdown
// 和executeExistingDelayedTasksAfterShutdown
// 前者允许在shutdown之后继续执行重复执行的任务
// 后者允许在shutdown之后继续执行延时执行的任务,
// 因此这里根据任务是否为periodic来决定采用哪个选项,然后
// 如果线程池正在运行,那么肯定可以执行
// 如果正在shutdown,那么要看选项的值是否为true来决定是否允许执行任务
// 如果不被允许的话,就会取消任务
if (!canRunInCurrentRunState(periodic))
cancel(false);
// 如果可以执行任务,对于不用重复执行的任务,直接执行即可
else if (!periodic)
ScheduledFutureTask.super.run();
// 对于需要重复执行的任务,则执行一次,然后reset
// 更新一下下次执行的时间,调用reExecutePeriodic更新任务在执行队列的
// 位置(其实就是添加到队列的末尾)
else if (ScheduledFutureTask.super.runAndReset()) {
setNextRunTime();
reExecutePeriodic(outerTask);
}
}
因此这里可以得出关于重复执行的实现:任务执行一次,Reset状态,重新加入到任务队列。
回到delayedExecute,它可以保证任务在准确时间点执行,来看delayedExecute是如果实现延迟执行的:
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();
}
}
乍看之下,发现也就是把任务加入到任务队列中,那么这个延时执行的功能是如何实现的,秘密就在任务队列的实现。
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
new DelayedWorkQueue());
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
ScheduledThreadPoolExecutor的任务队列不是普通的BlockingQueue,而是一个特殊的实现DelayedWorkQueue。下一篇文章就来说说这个DelayedWorkQueue。
《java.util.concurrent 包源码阅读》14 线程池系列之ScheduledThreadPoolExecutor 第一部分的更多相关文章
- 《java.util.concurrent 包源码阅读》 结束语
<java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...
- 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分
这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...
- 《java.util.concurrent 包源码阅读》04 ConcurrentMap
Java集合框架中的Map类型的数据结构是非线程安全,在多线程环境中使用时需要手动进行线程同步.因此在java.util.concurrent包中提供了一个线程安全版本的Map类型数据结构:Concu ...
- 《java.util.concurrent 包源码阅读》02 关于java.util.concurrent.atomic包
Aomic数据类型有四种类型:AomicBoolean, AomicInteger, AomicLong, 和AomicReferrence(针对Object的)以及它们的数组类型, 还有一个特殊的A ...
- 《java.util.concurrent 包源码阅读》17 信号量 Semaphore
学过操作系统的朋友都知道信号量,在java.util.concurrent包中也有一个关于信号量的实现:Semaphore. 从代码实现的角度来说,信号量与锁很类似,可以看成是一个有限的共享锁,即只能 ...
- 《java.util.concurrent 包源码阅读》06 ArrayBlockingQueue
对于BlockingQueue的具体实现,主要关注的有两点:线程安全的实现和阻塞操作的实现.所以分析ArrayBlockingQueue也是基于这两点. 对于线程安全来说,所有的添加元素的方法和拿走元 ...
- 《java.util.concurrent 包源码阅读》09 线程池系列之介绍篇
concurrent包中Executor接口的主要类的关系图如下: Executor接口非常单一,就是执行一个Runnable的命令. public interface Executor { void ...
- 《java.util.concurrent 包源码阅读》22 Fork/Join框架的初体验
JDK7引入了Fork/Join框架,所谓Fork/Join框架,个人解释:Fork分解任务成独立的子任务,用多线程去执行这些子任务,Join合并子任务的结果.这样就能使用多线程的方式来执行一个任务. ...
- 《java.util.concurrent 包源码阅读》24 Fork/Join框架之Work-Stealing
仔细看了Doug Lea的那篇文章:A Java Fork/Join Framework 中关于Work-Stealing的部分,下面列出该算法的要点(基本是原文的翻译): 1. 每个Worker线程 ...
随机推荐
- 页面固定DIV层CSS代码
有时候为了用户体验更好些,网页设计师会把网站导航放在一个固定的DIV层里面,不随滚动条滚动.本方法是利用CSS,position:fixed属性来固定层,fixed是特殊的absolute,即fixe ...
- 【广告】win10 uwp 水印图床 含代码
本文主要是广告我的软件. 图床可以加速大家写博客上传图片的时间,通过简化我们的操作来得到加速. 在写博客的时候,我们发现,我们需要上传一张图片,需要先打开图片,然后选择本地图片,然后上传. 但是我经常 ...
- keepalived实现nginx高可用
keepalived是什么 keepalived直译就是保持存活,在网络里面就是保持在线了,也就是所谓的高可用或热备,用来防止单点故障(单点故障是指一旦某一点出现故障就会导致整个系统架构的不可用)的发 ...
- 浅谈Django的生命周期和CBF和FBC
Django的生命周期和CBF和FBC 对于所有的web框架来说本质就是一个socket服务端,浏览器是socket客户端,客户端和服务端通信,字符串(Http协议):请求头和请求体 响应头+响应体 ...
- 局部刷新Ajax
1.1.1 Ajax的由来: 如下注册界面 界面在注册的时候,需要用户输入的信息有很多,假如我们将所有的数据都录入后,在点击会员注册按钮,然后将整个页面数据进行提交,此时如果该用户名已经被占用,那么 ...
- Linux_服务器_01_查看公网IP
在linux终端提示符下,输入以下命令: 精选: curl icanhazip.com/curl ifconfig.mecurl ipecho.net/plain 可以看到下图已经查询到公网IP地址了 ...
- 使用css3实现瀑布流布局效果
使用CSS3可以轻松实现瀑布流布局,但这种方法有个缺点,就是对于商城类型的网站,价格筛选时,并不能达到理想效果. 1.column-count 把div中的文本分为多少列 2.column-width ...
- java 随记
后台开发的过程中积累的关于java的杂记 架构 SSH框架 为什么要分层? 因为分层使代码变得清晰,容易写也容易阅读,更重要的是让代码扩展性更好,层与层之间的改动不会互相影响 各层的分工 dao--与 ...
- 安装jdk时出现java -version权限不够问题
今天在ubuntu上安装jdk的时候,最后测试java -version总是不行,出现了 bash: /home/jdk1.7.0_25/bin/java: 权限不够的问题 百度之后,在http:// ...
- nodejs运行前端项目
有时候我们会创建一些小项目,只有几个简单html,没有引入一些前端框架,也没有使用webpack,那我们要如何让代码在我们本地跑起来呢? 当然是有很多种方法,IIS.wampserver等等好多都可以 ...