无限创建线程的不足:
-
线程生命周期的开销非常高
-
资源消耗
闲置的线程会占用很多内存
-
稳定性
public interface Executor {
void execute(Runnable command);
}
newFixedThreadPool
创建一个固定长度的线程池,每当提交一个任务时就创建一个线程,直到达到线程池最大数量。
newCachedThreadPool
创建一个可缓存的线程池,如果线程池的当前规模超过了处理需求时,那么将回收空闲的线程,而当需求增加时,则可以添加新的线程。
newSingleThreadPool
是一个单线程的Executor
newScheduledThreadPool
创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer
ExecutorService
的生命周期有三种状态:运行、关闭和已终止
DelayQueue
实现了 BlockingQueue
并为ScheduledThreadPoolExecutor提供调度功能。
许多任务实际上都是存在延迟的计算--执行数据库查询,从网络上获取资源,或者计算某个复杂的功能。对于这些任务,Callable
是一个更好的抽象:它认为主入口点(即call
)将返回一个值,并有可能抛出一个异常。
Future
表示一个任务的生命周期,并提供了相应的方法来判断是否已经完成或取消,以及获取任务的结果和取消任务等。
只有当大量相互独立且同构的任务可以并发进行处理时,才能体现出将程序的工作负载分配到多个任务重带来的真正性能提升。
####:Executor 与 BlockingQueue
CompletionService
作用相当于一组计算的句柄,这与Future
作为单个计算的句柄非常相似
某个任务无法在指定时间内完成,那么将不再需要它的结果,此时可以放弃这个任务。
在支持时间限制的Future.get
中支持:当结果可用时,它将立刻返回,如果在指定时限内没有计算出结果,那么将抛出TimeoutException
- 用户请求取消
- 有时间限制的操作
- 应用程序事件
- 错误
- 关闭
一个可取消的任务必须拥有取消策略(Cancellation Policy)。
中断
调用interrupt
并不意味着立即停止目标线程正在进行的工作,而只是传递了请求中断的消息,然后线程在合适的时候(也称为取消点)中断自己。
通常,中断是实现取消的最合理方式
中断策略 最合理的中断策略是某种形式的线程级(Thread-Level)取消操作或服务级(Service-Level)取消操作:尽快退出,在必要时进行清理,通知某个所有者该线程已经退出。
响应中断
当调用可中断的阻塞函数时。有两种实用策略可用于处理InterruptException
:
- 传递异常
- 恢复中断状态