聊聊高并发(三十八)解析java.util.concurrent各个组件(十四) 理解Executor接口的设计
JUC包中除了一系列的同步类之外,就是Executor运行框架相关的类。对于一个运行框架来说,能够分为两部分
1. 任务的提交
2. 任务的运行。
这是一个生产者消费者模式,提交任务的操作是生产者,运行任务的线程相当于消费者。
Executor接口设计的目的是专注于任务的运行。和任务的提交解耦。
任务的提交由任务的创建者处理。
Executor接口封装了任务运行的细节,比方怎样使用线程,是否定时运行等等。
Executor接口非常easy,就一个execute方法。
public interface Executor {
void execute(Runnable command);
}
假设不使用Executor接口,直接用Thread显式地来运行一个Runnable。代码是这种
new Thread(new RunnableTask()).start()
而使用Executor接口运行Runnable的代码是这种
Executor executor = xxxExecutor;
executor.execute(new RunnableTask());
能够看到Executor接口的一个是屏蔽了任务运行的细节。
它全然能够直接使用Executor所在的线程直接同步运行任务
class DirectExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
也能够使用单独的线程来运行任务,从而异步的运行任务。
class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) {
new Thread(r).start();
}
}
《Java并发编程实战》一书中将任务运行的细节称为运行策略。运行策略定义了任务运行的What, Where, When, How
1. 在什么(What)线程中运行任务?
2. 任务依照什么(What)顺序运行(FIFO,LIFO,优先级)
3. 有多少个(How Many)任务能并发运行
4. 在队列中有(How Many)任务在等待运行
5. 假设系统因为过载Overload而须要拒绝一个任务。那么应该选择哪一个(Which)任务?怎样(How)通知应用程序有任务被拒绝
6. 在运行一个任务之前或之后,应该进行哪些(What)动作?
这几点都是设计一个运行框架须要考虑的事情。比方ThreadPoolExecutor攻克了线程池的问题,ExecutorService攻克了运行任务生命周期管理的问题。ScheduleExecutorService攻克了定时运行任务的问题。
以下这个在Executor JavaDoc里的串行运行任务的Exector,能够看到怎样扩展Executor来自己定义运行的策略。
1. 封装了一个ArrayDeque队列来存放待运行的Runnable任务
2. 真正用来运行任务的Executor对象
3. 当前要运行的任务active对象
4. SerialExecutor的execute方法先讲传入的Runnable任务再封装一层,增加到tasks队列,保证这个任务运行完后会去调用scheduleNext()运行下一个任务。然后推断active对象是否是null,表示是第一次运行。就显式地运行scheduleNext().
5. scheduleNext()方法从队列中取任务运行
6. execute()和scheduleNext()都是synchronized方法。保证串行运行。
class SerialExecutor implements Executor {
final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
final Executor executor;
Runnable active;
SerialExecutor(Executor executor) {
this.executor = executor;
}
public synchronized void execute(final Runnable r) {
tasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (active == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((active = tasks.poll()) != null) {
executor.execute(active);
}
}
}}
聊聊高并发(三十八)解析java.util.concurrent各个组件(十四) 理解Executor接口的设计的更多相关文章
- 聊聊高并发(二十)解析java.util.concurrent各个组件(二) 12个原子变量相关类
这篇说说java.util.concurrent.atomic包里的类,总共12个.网上有非常多文章解析这几个类.这里挑些重点说说. watermark/2/text/aHR0cDovL2Jsb2cu ...
- 谈论高并发(三十)解析java.util.concurrent各种组件(十二) 认识CyclicBarrier栅栏
这次谈话CyclicBarrier栅栏,如可以从它的名字可以看出,它是可重复使用. 它的功能和CountDownLatch类别似,也让一组线程等待,然后开始往下跑起来.但也有在两者之间有一些差别 1. ...
- 聊聊高并发(四十)解析java.util.concurrent各个组件(十六) ThreadPoolExecutor源代码分析
ThreadPoolExecutor是Executor运行框架最重要的一个实现类.提供了线程池管理和任务管理是两个最主要的能力.这篇通过分析ThreadPoolExecutor的源代码来看看怎样设计和 ...
- 聊聊高并发(二十九)解析java.util.concurrent各个组件(十一) 再看看ReentrantReadWriteLock可重入读-写锁
上一篇聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁 讲了可重入读写锁的基本情况和基本的方法,显示了怎样 ...
- 聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore
前几篇分析了一下AQS的原理和实现.这篇拿Semaphore信号量做样例看看AQS实际是怎样使用的. Semaphore表示了一种能够同一时候有多个线程进入临界区的同步器,它维护了一个状态表示可用的票 ...
- 谈论高并发(二十二)解决java.util.concurrent各种组件(四) 深入了解AQS(二)
上一页介绍AQS其基本设计思路以及两个内部类Node和ConditionObject实现 聊聊高并发(二十一)解析java.util.concurrent各个组件(三) 深入理解AQS(一) 这篇说一 ...
- 聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁
这篇讲讲ReentrantReadWriteLock可重入读写锁,它不仅是读写锁的实现,而且支持可重入性. 聊聊高并发(十五)实现一个简单的读-写锁(共享-排他锁) 这篇讲了怎样模拟一个读写锁. 可重 ...
- 聊聊高并发(三十九)解析java.util.concurrent各个组件(十五) 理解ExecutorService接口的设计
上一篇讲了Executor接口的设计,目的是将任务的运行和任务的提交解耦.能够隐藏任务的运行策略.这篇说说ExecutorService接口.它扩展了Executor接口,对Executor的生命周期 ...
- 聊聊高并发(二十四)解析java.util.concurrent各个组件(六) 深入理解AQS(四)
近期总体过了下AQS的结构.也在网上看了一些讲AQS的文章,大部分的文章都是泛泛而谈.又一次看了下AQS的代码,把一些新的要点拿出来说一说. AQS是一个管程.提供了一个主要的同步器的能力,包括了一个 ...
随机推荐
- 52. 模版和设计元素——Lotus Notes的代码重用
不论是理论上还是实用上,代码重用都是编程的一个重要议题.可以从两个角度来讨论代码重用. 一是逻辑上代码以怎样的方式被重用.既可以通过面向对象的思想普及以来耳熟能详的继承的方式.比如先建了一个车的基类, ...
- ANDROID自定义视图——onMeasure流程,MeasureSpec详解
简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量——onMeasure():决定View的大小 2.布局——onLayout():决定View在ViewGroup中的位置 3. ...
- Git Hub,eclipse pull 出现问题
一般在eclise里面使用geithub,之后会出现无法pull,或者pull 报错的问题.这里需要修改本地库的配置文件 The current branch is not configured fo ...
- MonkeyRunner 学习
monkeyrunner 本文档中包含 一个简单的monkeyrunner示例程序 monkeyrunner API简介 运行monkeyrunner monkeyrunner内建帮助 使用插件扩展m ...
- SetWindowLong
SetWindowLong函数介绍 收藏 SetWindowLong函数介绍 SetWindowLong Unicode 函数原型 LONG SetWindowLong(hwnd,nIndex,lNe ...
- asp.net iis URLRewrite 实现方法详解
原文 asp.net iis URLRewrite 实现方法详解 实现非常简单首先你要在你的项目里引用两个dll:actionlessform.dll.urlrewriter.dll,真正实现重写的是 ...
- [置顶] ※数据结构※→☆线性表结构(queue)☆============队列 顺序存储结构(queue sequence)(八)
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表.进行插入操作的端称为队尾,进行删除操作的 ...
- 与众不同 windows phone (5) - Chooser(选择器)
原文:与众不同 windows phone (5) - Chooser(选择器) [索引页][源码下载] 与众不同 windows phone (5) - Chooser(选择器) 作者:webabc ...
- Atitit.jquery 版本号新特性attilax总结
Atitit.jquery 版本号新特性attilax总结 1. Jq1.4 1 2. 1.5 1 3. 1.6 3 4. Jq1.7 3 ⒉提升了事件委派时的性能有了大幅度的提升.尤其是在ie7下: ...
- [置顶] EasyMock构建单元测试
1. 背景 单元测试作为程序的基本保障.很多时候构建测试场景是一件令人头疼的事.因为之前的单元测试都是内部代码引用的,环境自给自足.开发到了一定程度,你不得不到开始调用外部的接口来完成你的功能.而外部 ...