在java中java executorservice是框架吗

在Java中,使用线程来异步执行任务。Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源。同时,为每一个任务创建一个新线程来执行,这种策略可能会使处于高负荷状态的应用最终崩溃。
Java线程既是工作单元,也是执行单元。从JDK1.5开始,把工作单元与执行机制分离开来。工作单元包括Runnable 和 Callable,而执行机制由Executor框架提供。
Executor框架简介
Executor框架的两级调度模型
在HotSpot VM的线程模型中,Java线程被一对一映射为本地操作系统线程。Java线程启动时会创建一个本地操作系统线程;当Java线程终止时,这个操作系统线程也会被回收。操作系统会调用所有线程并将他们分配给可用的CPU。
可以将此种模式分为两层,在上层,Java多线程程序通常把应用程序分解为若干任务,然后使用用户级的调度器(Executor框架)讲这些任务映射为固定数量的线程;在底层,操作系统内核将这些线程映射到硬件处理器上。
两级调度模型的示意图:
从图中可以看出,该框架用来控制应用程序的上层调度(下层调度由操作系统内核控制,不受应用程序的控制)。
Executor框架的结构和成员
Executor框架的结构
包括被执行任务需要实现的接口:Runnable接口和Callable接口
2. 任务的执行
包括任务执行机制的核心接口Executor,以及继承自Executor的ExecutorService接口。
Executor框架有两个关键类实现了ExecutorService接口:和 ScheduledThreadPoolExecutor
3. 异步计算的结果
包括Future和实现Future接口的FutureTask类。
Executor框架的类与接口
Executor是一个接口,他是Executor框架的基础,它将任务的提交与任务的执行分离。
是线程池的核心实现类,用来执行被提交的任务。
ScheduledThreadPoolExecutor是一个实现类,可以在给定的延迟后运行命令,或者定期执行命令。ScheduledThreadPoolExecutor 比 Timer 更灵活,功能更强大。
Future接口和它的实现FutureTask类,代表异步计算的结果。
Runnable和Callable接口的实现类,都可以被ThreadPoolExecutor 或&ScheduledThreadPoolExecutor 执行。
Executor框架的使用
&先来看个图:
主线程首先要创建实现 Runnable接口或者Callable接口的任务对象。工具类Executors可以把一个Runnable对象封装为一个Callable对象
Executors.callable(Runnale task);
Executors.callable(Runnable task, Object resule);
然后可以把Runnable对象直接交给ExecutorService执行
ExecutorServicel.execute(Runnable command);
或者也可以把Runnable对象或Callable对象提交给ExecutorService执行
ExecutorService.submit(Runnable task);
如果执行ExecutorService.submit(...),ExecutorService将返回一个实现Future接口的对象(到目前为止的JDK中,返回的是FutureTask对象)。由于FutureTask实现了Runnable接口,我们也可以创建FutureTask类,然后直接交给ExecutorService执行。  
最后,主线程可以执行FutureTask.get()方法来等待任务执行完成。主线程也可以执行FutureTask.cancel(boolean mayInterruptIfRunning)来取消此任务的执行。
&ThreadPoolExecutor详解
&Executor框架最核心的类是
&ThreadPoolExecutor的组件构成
corePool:核心线程池的大小
maximumPool:最大线程池的大小
BlockingQueue:用来暂时保存任务的工作队列
RejectedExecutionHandler:当ThreadPoolExecutor已经关闭或ThreadPoolExecutor已经饱和时(达到了最大线程池的大小且工作队列已满),execute()方法将要调用的Handler。
Executor 可 以 创 建 3 种 类 型 的 线 程 池:
&1. FixedThreadPool
创建固定长度的线程池,每次提交任务创建一个线程,直到达到线程池的最大数量,线程池的大小不再变化。
这个线程池可以创建固定线程数的线程池。特点就是可以重用固定数量线程的线程池。它的构造源码如下:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue&Runnable&());
FixedThreadPool的corePoolSize和maxiumPoolSize都被设置为创建FixedThreadPool时指定的参数nThreads。
0L则表示当线程池中的线程数量操作核心线程的数量时,多余的线程将被立即停止
最后一个参数表示FixedThreadPool使用了无界队列LinkedBlockingQueue作为线程池的做工队列,由于是无界的,当线程池的线程数达到corePoolSize后,新任务将在无界队列中等待,因此线程池的线程数量不会超过corePoolSize,同时maxiumPoolSize也就变成了一个无效的参数,并且运行中的线程池并不会拒绝任务。
FixedThreadPool运行图如下
执行过程如下:
1.如果当前工作中的线程数量少于corePool的数量,就创建新的线程来执行任务。
2.当线程池的工作中的线程数量达到了corePool,则将任务加入LinkedBlockingQueue。
3.线程执行完1中的任务后会从队列中去任务。
注意LinkedBlockingQueue是无界队列,所以可以一直添加新任务到线程池。
2. SingleThreadExecutor  
SingleThreadExecutor是使用单个worker线程的Executor。特点是使用单个工作线程执行任务。它的构造源码如下:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue&Runnable&()));
SingleThreadExecutor的corePoolSize和maxiumPoolSize都被设置1。
其他参数均与FixedThreadPool相同,其运行图如下:
执行过程如下:
1.如果当前工作中的线程数量少于corePool的数量,就创建一个新的线程来执行任务。
2.当线程池的工作中的线程数量达到了corePool,则将任务加入LinkedBlockingQueue。
3.线程执行完1中的任务后会从队列中去任务。
注意:由于在线程池中只有一个工作线程,所以任务可以按照添加顺序执行。
&3. CachedThreadPool
&CachedThreadPool是一个&无限&容量的线程池,它会根据需要创建新线程。特点是可以根据需要来创建新的线程执行任务,没有特定的corePool。下面是它的构造方法:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue&Runnable&());
CachedThreadPool的corePoolSize被设置为0,即corePool为空;maximumPoolSize被设置为Integer.MAX_VALUE,即maximum是无界的。这里keepAliveTime设置为60秒,意味着空闲的线程最多可以等待任务60秒,否则将被回收。
CachedThreadPool使用没有容量的SynchronousQueue作为主线程池的工作队列,它是一个没有容量的阻塞队列。每个插入操作必须等待另一个线程的对应移除操作。这意味着,如果主线程提交任务的速度高于线程池中处理任务的速度时,CachedThreadPool会不断创建新线程。极端情况下,CachedThreadPool会因为创建过多线程而耗尽CPU资源。其运行图如下:
执行过程如下:
1.首先执行SynchronousQueue.offer(Runnable task)。如果在当前的线程池中有空闲的线程正在执行SynchronousQueue.poll(),那么主线程执行的offer操作与空闲线程执行的poll操作配对成功,主线程把任务交给空闲线程执行。,execute()方法执行成功,否则执行步骤2
2.当线程池为空(初始maximumPool为空)或没有空闲线程时,配对失败,将没有线程执行SynchronousQueue.poll操作。这种情况下,线程池会创建一个新的线程执行任务。
3.在创建完新的线程以后,将会执行poll操作。当步骤2的线程执行完成后,将等待60秒,如果此时主线程提交了一个新任务,那么这个空闲线程将执行新任务,否则被回收。因此长时间不提交任务的CachedThreadPool不会占用系统资源。
SynchronousQueue是一个不存储元素阻塞队列,每次要进行offer操作时必须等待poll操作,否则不能继续添加元素。
参考书籍:《Java并发编程的艺术》,《Java并发编程实战》,《Java高并发程序设计》
更多内容:
阅读(...) 评论()> 博客详情
读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。
欢迎star、fork,读书笔记系列会同步更新
j360-jdk-thread/me.j360.jdk.concurrent
本系列分4篇
本书前三章分别为
并发编程的挑战,也就是并发编程的缘由所在
底层的实现原理
java内存模型
分别从cpu x86,x64以及内存模型等概念中描述java对并发编程的实现和控制,概念较为底层和基础,读书笔记略过前三章直接从第四章应用实现及原理基础开始。
并发编程基础
java中的锁
并发容器和框架(重点)
13个操作原子类
java并发工具类
Execurot框架
写到第六七节终于有点小激动了,因为到这里结束就意味着可以开开心心的去写高并发底层了,但实际上开发中用到最多的还是线程池的设计和并发Executor的使用,在下一节会对这两节的内容用一套完整的框架来实践线程池和Executor的使用案例,其实还有一本书《七周七并发模型》第一个模型几乎就把这本书完整的知识点概括完了,但是因为作者针对的面不同,并发模型这本书更多的讲述如何用好并发框架,达到最优的效果,并发编程的艺术更多的是介绍原理和概念,一并起来看收获匪浅。
好了,再来复习下线程池吧,在之前的线程池的设计中使用的是jdk5之前的设计思路,在jdk5之后使用并发框架实现的线程池将会容易的多,但是性能和效率却好得多。
先看一张ThreadPoolExecutor执行execute方法的执行示意图
执行方法分4种情况
如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(这一个过程需要获取全局锁)
如果当前运行线程数等于或者多余corePoolSize,则加入到队列BlockQueue
如果无法加入到BlockQueue(队列已满),则创建新的线程来处理任务,(需要获取全局锁)
如果创建的线程将使得当前运行的线程数量大于MaximunPoolSize,任务将被拒绝,并调用非常重要的RejuectExecutionHandler.rejectExecution()方法
线程池的创建
new&ThreadPoolExecutor(corePoolSize,maximunPoolSize,keepAliveTime,milliseconds,runnableTaskQueue,handler);
corePoolSize,线程池的基本大小
runnableTaskQueue:用于保存等待执行的任务的阻塞队列,可以有以下选择
ArrayBlockingQueue
LinkedBlockingQueue
synchronousQueue
priorityBlockingQueue
maximumPoolSze:线程池最大数量
ThreadFacotry:用于设置创建线程的工厂
RejectedExecutionHandler:饱和策略
keepAliveTime:线程保持活动的时间
TimeUtil:线程保持活动的单位
线程池提交任务
分别为execute()/submit()
threadPool.execute(new&Runnable(){
&&&&@override
&&&&public&void&run(){
&&&&&&&&//run
Future&Object&&future&=&executor.submit(harReturnValuetask);
&Object&s&=&futrue.get();
}catch(InterruptedException&e){
}catch(ExecutionException&e){
&//关闭线程池
&executor.shutdown();
关闭线程池
shutdown()、shutdownNow()
线程池的监控
taskCount、completedTaskCount、largestPoolSize、getpoolSize,getActiveCount
通过重写线程池的beforeExecutor、afterExecutor、terminated方法
7、Executor框架
Executor框架由3大部分组成
任务:被执行任务需要实现的接口Runnable、Callable
任务的进行:任务执行机制的核心接口Executor,继承Executor的ExecutorService
异步计算的结果:Future和实现了Future接口的FutureTask类
Execurot是Executor框架的基础,将任务的提交和任务的执行分离开来
支付宝支付
微信扫码支付
打赏金额: ¥
已支付成功
打赏金额: ¥博客分类:
1、Executor 框架:异步任务执行框架。提供了对生命周期的支持,以及统计信息收集,应用程序管理和性能监视等机制。
·基于生产者-消费者模式。
·将任务提交过程与任务执行过程解耦,并且用Runnable来表示任务
2、线程池
·newFixedThreadPool:创建一个固定长度的线程池。
·newCachedThreadPool:创建一个可缓存的线程池。
·newSingleThreadPool:是一个单线程的线程池,按照任务在队列中的顺序来串行执行[FIFO,LIFO,优先级]等。
·newScheduledThreadPool:创建一个固定长度的线程池,并且以定时或者延时的方式执行任务。
3、Executor生命周期
·ExecutorService的生命周期有3种状态:运行,关闭,已终止。
·ExecutorService创建时就处于运行状态。
·shutdown方法将执行平缓的关闭过程:不接受新的任务,同时等待已提交的任务执行完成,保护还未开始执行的任务
4、Executor类只提供线程池的功能,并不提供生命周期监控的功能。
&& ExecutorService类不仅提供了线程池,而且具有生命周期监控等功能。
5、Executor.execute(Runnable command)&
&& Future&T& future = ExecutorService.submit(Callable&T& task)
&& List&Future&T&& list = ExecutorService.invokeAll(Collection&Callable&T&& tasks, timeout, unit)
import java.util.concurrent.C
import java.util.concurrent.ExecutionE
import java.util.concurrent.ExecutorS
import java.util.concurrent.E
import java.util.concurrent.F
import java.util.concurrent.TimeU
import java.util.concurrent.TimeoutE
public class TaskExecution {
private static final ExecutorService exec = Executors.newFixedThreadPool(4);
public static void main(String[] args) {
Callable&String& task = new Callable&String&() {
public String call() throws Exception {
Thread.sleep(1000);
return "success";
Future&String& future= exec.submit(task);
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("isTerminate = "+exec.isTerminated());
System.out.println("future.get = "+future.get(800,TimeUnit.NANOSECONDS));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
exec.shutdown();
} catch (ExecutionException e) {
e.printStackTrace();
exec.shutdown();
} catch (TimeoutException e) {
e.printStackTrace();
future.cancel(true);
exec.shutdown();
System.out.println("------------");
lemon_1227
浏览: 19225 次
来自: 杭州
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'博客分类:
浏览: 6246 次
来自: 南京
toknowme 写道InstanceMBean 这个类是哪里 ...
toknowme 写道InstanceMBean 这个类是哪里 ...
InstanceMBean 这个类是哪里来的啊?
有点意思 昊子!哈哈虽然很晚了,不过我还是很有兴趣去动手练习下 ...
昊子,太谦虚了!你在我心中就是大神!
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'& & & &Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务的线程相当于消费者,并用Runnable来表示任务,Executor的实现还提供了对生命周期的支持,以及统计信息收集,应用程序管理机制和性能监视等机制。
1.Exexctor简介
Executor的UML图:(常用的几个接口和子类)
Executor:一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable command),
ExecutorService:是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法,以及可跟踪一个或多个异步任务执行状况返回Future的方法
AbstractExecutorService:ExecutorService执行方法的默认实现
ScheduledExecutorService:一个可定时调度任务的接口
ScheduledThreadPoolExecutor:ScheduledExecutorService的实现,一个可定时调度任务的线程池
ThreadPoolExecutor:线程池,可以通过调用Executors以下静态工厂方法来创建线程池并返回一个ExecutorService对象:
2.ThreadPoolExecutor构造函数的各个参数说明
ThreadPoolExecutor方法签名:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue&Runnable& workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) //后两个参数为可选参数
参数说明:
corePoolSize:核心线程数,如果运行的线程少于corePoolSize,则创建新线程来执行新任务,即使线程池中的其他线程是空闲的
maximumPoolSize:最大线程数,可允许创建的线程数,corePoolSize和maximumPoolSize设置的边界自动调整池大小:
corePoolSize&&运行的线程数&&maximumPoolSize:仅当队列满时才创建新线程
corePoolSize=运行的线程数=&maximumPoolSize:创建固定大小的线程池
keepAliveTime:如果线程数多于corePoolSize,则这些多余的线程的空闲时间超过keepAliveTime时将被终止
unit:keepAliveTime参数的时间单位
workQueue:保存任务的阻塞队列,与线程池的大小有关:
& 当运行的线程数少于corePoolSize时,在有新任务时直接创建新线程来执行任务而无需再进队列
& 当运行的线程数等于或多于corePoolSize,在有新任务添加时则选加入队列,不直接创建线程
& 当队列满时,在有新任务时就创建新线程
threadFactory:使用ThreadFactory创建新线程,默认使用defaultThreadFactory创建线程
handle:定义处理被拒绝任务的策略,默认使用ThreadPoolExecutor.AbortPolicy,任务被拒绝时将抛出RejectExecutorException
3.Executors:提供了一系列静态工厂方法用于创建各种线程池
& &newFixedThreadPool:创建可重用且固定线程数的线程池,如果线程池中的所有线程都处于活动状态,此时再提交任务就在队列中等待,直到有可用线程;如果线程池中的某个线程由于异常而结束时,线程池就会再补充一条新线程。
方法签名:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
//使用一个基于FIFO排序的阻塞队列,在所有corePoolSize线程都忙时新任务将在队列中等待
new LinkedBlockingQueue&Runnable&());
& &newSingleThreadExecutor:创建一个单线程的Executor,如果该线程因为异常而结束就新建一条线程来继续执行后续的任务
方法签名:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
//corePoolSize和maximumPoolSize都等于,表示固定线程池大小为1
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue&Runnable&()));
& &newScheduledThreadPool:创建一个可延迟执行或定期执行的线程池
方法签名:
例1:(使用newScheduledThreadPool来模拟心跳机制)
1 public class HeartBeat {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
Runnable task = new Runnable() {
public void run() {
System.out.println("HeartBeat.........................");
executor.scheduleAtFixedRate(task,5,3, TimeUnit.SECONDS);
//5秒后第一次执行,之后每隔3秒执行一次
HeartBeat....................... //5秒后第一次输出
HeartBeat....................... //每隔3秒输出一个
& &newCachedThreadPool:创建可缓存的线程池,如果线程池中的线程在60秒未被使用就将被移除,在执行新的任务时,当线程池中有之前创建的可用线程就重 & & &用可用线程,否则就新建一条线程
方法签名:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
//使用同步队列,将任务直接提交给线程
new SynchronousQueue&Runnable&());
public class ThreadPoolTest {
public static void main(String[] args) throws InterruptedException {
ExecutorService threadPool = Executors.newCachedThreadPool();//线程池里面的线程数会动态变化,并可在线程线被移除前重用
for (int i = 1; i &= 3; i ++) {
int task =
//10个任务
//TimeUnit.SECONDS.sleep(1);
threadPool.execute(new Runnable() {
//接受一个Runnable实例
public void run() {
System.out.println("线程名字: " + Thread.currentThread().getName() +
任务名为: "+task);
输出:(为每个任务新建一条线程,共创建了3条线程)
线程名字: pool-1-thread-1 任务名为: 1
线程名字: pool-1-thread-2 任务名为: 2
线程名字: pool-1-thread-3 任务名为: 3
去掉第6行的注释其输出如下:(始终重复利用一条线程,因为newCachedThreadPool能重用可用线程)
线程名字: pool-1-thread-1 任务名为: 1
线程名字: pool-1-thread-1 任务名为: 2
线程名字: pool-1-thread-1 任务名为: 3
通过使用Executor可以很轻易的实现各种调优 &管理 &监视 &记录日志和错误报告等待。
4.Executor的生命周期
ExecutorService提供了管理Eecutor生命周期的方法,ExecutorService的生命周期包括了:运行 &关闭和终止三种状态。
ExecutorService在初始化创建时处于运行状态。
shutdown方法等待提交的任务执行完成并不再接受新任务,在完成全部提交的任务后关闭
shutdownNow方法将强制终止所有运行中的任务并不再允许提交新任务
可以将一个Runnable(如例2)或Callable(如例3)提交给ExecutorService的submit方法执行,最终返回一上Futire用来获得任务的执行结果或取消任务
例3:(任务执行完成后并返回执行结果)
public class CallableAndFuture {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future&String& future = executor.submit(new Callable&String&() {
//接受一上callable实例
public String call() throws Exception {
return "MOBIN";
System.out.println("任务的执行结果:"+future.get());
任务的执行结果:MOBIN
ExecutorCompletionService:实现了CompletionService,将执行完成的任务放到阻塞队列中,通过take或poll方法来获得执行结果
例4:(启动10条线程,谁先执行完成就返回谁)
public class CompletionServiceTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(10);
//创建含10.条线程的线程池
CompletionService completionService = new ExecutorCompletionService(executor);
for (int i =1; i &=10; i ++) {
int result =
completionService.submit(new Callable() {
public Object call() throws Exception {
Thread.sleep(new Random().nextInt(5000));
//让当前线程随机休眠一段时间
System.out.println(completionService.take().get());
//获取执行结果
输出结果可能每次都不同(在1到10之间)
通过Executor来设计应用程序可以简化开发过程,提高开发效率,并有助于实现并发,在开发中如果需要创建线程可优先考虑使用Executor
阅读(...) 评论()}

我要回帖

更多关于 java executorservice 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信