ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Executor家族一览

2019-07-07 16:57:33  阅读:255  来源: 互联网

标签:Runnable 实例 一览 家族 Callable Future 线程 Executor 执行


笔记来自于Java多线程编程实战指南

这次没有用MD来写笔记,可能排版有点难受


Runnable / Callable 接口是对任务处理逻辑的抽象,也就是说不管怎样的处理逻辑,均有同一的签名方法:run/call,而不关心具体的处理逻辑

Exectuor接口是对任务的执行进行的抽象:也就是说任务提交方(生产者)只需知道execute可使指定的任务被执行,不关心具体的执行细节(比如是由工作者进程还是怎样的线程池来执行)

接口仅定义了 void execute(Runnable command)

抽象的好处:
1.提交与执行解耦
2.信息隐藏/关注点分离,就是OOP中的封装
3.屏蔽同步执行和异步执行的差异,提交到ThreadPoolExecutor就是异步执行,自行implement接口直接在execute中调用run就是同步执行

Executor缺点:
1.只能为客户端代码执行任务,无法将任务结果返回
2.实现类需要维护一些工作者线程,当不再需要该Executor实例时,需要主动释放资源

因此作为改进新增ExecutorService接口(其默认实现是ThreadPoolExecutor)
1.提供submit接受Callable和Runnable并返回Future实例
2.提供shutdown和shutdownNow来关闭相应服务(如关闭维护的工作者线程), PS.shutdownNow内部调用Interrupt方法来实现

util类Executors大概功能一览
1.提供一些好用的ExecutorService线程池实例,如newCachedThreadPool/newFixedThreadPool/newSingleThreadPool(后者无法转换hreadPoolExecutor实例)
2.提供Runnable转换Callable实例
3.返回默认线程工厂defaultThreadFactory

线程池调优选择
Executors给出的各种线程池实例实际上是调用
new ThreadPoolExecutor(corePoolSize,maxPoolSize,keepAlive,timeUnit,blockingQueue,threadFactory,rejectExecutionHandler)(够长吧
其中keepAlive和timeUnit用于指定空闲时间,仅负责处理超过核心大小的部分
线程池任务存入工作队列是调用非阻塞的offer(e)
handler用于超过线程池阈值时的处理,该RejectExecutionHandler接口仅定义单一的方法:rejectExecution(runnable,threadPoolExecutor),也有帮你搞定的util实现类:
AbortPolicy(异常)/DiscardPolicy(丢弃当前)/DiscardOldestPolicy(丢弃queue中最老的任务,重新尝试)/CallerRunsPolicy(客户端Caller线程执行)

newCachedThreadPool适用于大量耗时短且提交频繁的任务(耗时过长会导致线程过多而上下文切换频繁),队列使用SynchronousQueue
newFixedThreadPool核心线程池大小=最大线程池大小keepAlive=0(空闲不清理),队列使用LinkedBlockingQueue
newSingleThreadPool适用于单/多生产者但消费者模式,也可用于执行非线程安全对象(不愿意为此加锁)

PS.线程池实例可接受ThreadFactory参数,可用于标准化线程的生产流程(统一配置),比如书中P316的XThreadFactory为线程所做的大概有
1.关联UncaughtExceptionHandler
2.确保用户线程/线程名称含义/优先级..
3.更友好的toString

CompletionService用于一次性批量提交异步任务,暂略

题外话:关于Future和FutureTask

Future接口实例可认为是任务处理结果句柄,大概有那么多定义的方法
1.get()会阻塞以获得执行结果(需要处理InterruptedException和ExecutionException),因此有一个原则是尽量早的submit,尽量晚的get
2.cancel(mayInterrupted)
3.isDone()/isCancelled()/get(time,unit)
也就是说Future使得获知任务的不只是结果(Callable返回的V),还有当前任务的执行情况,不过要处理的异常蛮多的...(还没写全
注意判断完成的情况比较复杂

Runnable优点:可交给简单的工作者线程/Executor的execute/线程池的submit(关于submit需要后面补充)
Runnable缺点:无法得知结果

Callable优点:能得知结果
Callable缺点:只能递交给线程池执行

注意点:Runnable作为executorService的参数时也是可以返回Future的,但源码实现中(具体看AbstractExecutorService的实现)是调用newTaskFor(你可认为就是用了callable转换方法)直接给null作为结果(返回的具体是RunnableFuture,下面会说它是啥)...

FutureTask是Future接口的唯一实现类,它直接实现自RunnableFuture接口
(而RunnableFuture继承自Runnable和Future,可作为两者使用)
其目的就是要结合Runnable和Callable的优点,具体地,就是你实现了Callable示例,直接用它来构造出FutureTask便能转换成Runnable实例,由多态确保能递交给简单的工作者线程/Executor的execute/线程池的submit(具体看源码吧,说起来真绕)
除此以外,FutureTask还能拥有Future的特点,既获得结果(Callable的结果通过get得到而不会因为"转换"成Runnable而丢失),并且能拥有此前提到的关于Future获得任务执行状况和取消的方法
其实类的名字已经说清楚了,既是Future,也是Task

标签:Runnable,实例,一览,家族,Callable,Future,线程,Executor,执行
来源: https://www.cnblogs.com/caturra/p/11146693.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有