笔记来自于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