Java并发编程实践 目录
并发编程 04—— 闭锁CountDownLatch 与 栅栏CyclicBarrier
并发编程 06—— CompletionService : Executor 和 BlockingQueue
并发编程 10—— 任务取消 之 关闭 ExecutorService
并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性
并发编程 13—— 线程池的使用 之 配置ThreadPoolExecutor 和 饱和策略
在之前的章节中,看到ExecutorService提供了两种关闭方法:使用shutdown正常关闭,以及使用shutdownNow 强行关闭。在进行强行关闭时, shutdownNow 首先关闭当前正在执行的任务,然后返回所有尚未启动的任务清单。
这两种关闭方式的差别在于各自的安全性和响应性:强行关闭的速度更快,但风险也更大,因为任务很可能在执行到一半时被结束;而正常关闭虽然速度慢,但却更安全,因为 ExecutorService 会一直等到队列中的所有任务都执行完成后才关闭。在其他拥有线程的服务中也应该考虑提供类似的关闭方式以供选择。
简单的程序可以直接在main 函数中启动和关闭全局的 ExecutorService。而在复杂程序中,通常会将 ExecutorService 封装在某个更高级别的服务中,并且该服务能提供自己的生命周期方法,例如下面程序清单中,LogService的一种变化形式,它将管理线程的工作委托给一个 ExecutorService ,而不是由其自行管理。通过封装 ExecutorService,可以将所有权链从应用程序扩展到服务以及线程,所有权链上的各个成员都将管理它所拥有的服务或线程的生命周期。
/**
* 7.16 封装ExecutorService实现日志服务
* @ClassName: LogService2
* @author xingle
* @date 2014-11-12 下午4:19:07
*/
public class LogService2 {
private final ExecutorService exec = Executors.newSingleThreadExecutor();
private final PrintWriter writer; public LogService2(PrintWriter writer){
this.writer = writer;
} /**
* 产生日志
* @param msg 日志内容
* @throws InterruptedException
*/
public void log(String msg){
exec.execute(new WriteTask(msg));
} /**
* 停止日志服务
* @throws InterruptedException
*/
public void stop(long timeout, TimeUnit unit) throws InterruptedException {
try {
exec.shutdown(); // 平缓关闭服务
// 关闭服务后, 阻塞到所有任务被执行完毕或者超时发生,或当前线程被中断
exec.awaitTermination(timeout, unit);
} finally {
writer.close();
}
}
} class WriteTask implements Runnable
{
public WriteTask(String msg) {
} public void run()
{
//do something here
}
}