Java並發編程實踐 目錄
並發編程 04—— 閉鎖CountDownLatch 與 柵欄CyclicBarrier
並發編程 06—— CompletionService : Executor 和 BlockingQueue
並發編程 10—— 任務取消 之 關閉 ExecutorService
並發編程 12—— 任務取消與關閉 之 shutdownNow 的局限性
並發編程 13—— 線程池的使用 之 配置ThreadPoolExecutor 和 飽和策略
並發編程 20—— AbstractQueuedSynchronizer 深入分析
在之前的章節中,看到ExecutorService提供了兩種關閉方法:使用shutdown正常關閉,以及使用shutdownNow 強行關閉。在進行強行關閉時, shutdownNow 首先關閉當前正在執行的任務,然后返回所有尚未啟動的任務清單。
這兩種關閉方式的差別在於各自的安全性和響應性:強行關閉的速度更快,但風險也更大,因為任務很可能在執行到一半時被結束;而正常關閉雖然速度慢,但卻更安全,因為 ExecutorService 會一直等到隊列中的所有任務都執行完成后才關閉。在其他擁有線程的服務中也應該考慮提供類似的關閉方式以供選擇。
簡單的程序可以直接在main 函數中啟動和關閉全局的 ExecutorService。而在復雜程序中,通常會將 ExecutorService 封裝在某個更高級別的服務中,並且該服務能提供自己的生命周期方法,例如下面程序清單中,LogService的一種變化形式,它將管理線程的工作委托給一個 ExecutorService ,而不是由其自行管理。通過封裝 ExecutorService,可以將所有權鏈從應用程序擴展到服務以及線程,所有權鏈上的各個成員都將管理它所擁有的服務或線程的生命周期。
1 /** 2 * 7.16 封裝ExecutorService實現日志服務 3 * @ClassName: LogService2 4 * @author xingle 5 * @date 2014-11-12 下午4:19:07 6 */ 7 public class LogService2 { 8 private final ExecutorService exec = Executors.newSingleThreadExecutor(); 9 private final PrintWriter writer; 10 11 public LogService2(PrintWriter writer){ 12 this.writer = writer; 13 } 14 15 /** 16 * 產生日志 17 * @param msg 日志內容 18 * @throws InterruptedException 19 */ 20 public void log(String msg){ 21 exec.execute(new WriteTask(msg)); 22 } 23 24 /** 25 * 停止日志服務 26 * @throws InterruptedException 27 */ 28 public void stop(long timeout, TimeUnit unit) throws InterruptedException { 29 try { 30 exec.shutdown(); // 平緩關閉服務 31 // 關閉服務后, 阻塞到所有任務被執行完畢或者超時發生,或當前線程被中斷 32 exec.awaitTermination(timeout, unit); 33 } finally { 34 writer.close(); 35 } 36 } 37 } 38 39 class WriteTask implements Runnable 40 { 41 public WriteTask(String msg) { 42 } 43 44 public void run() 45 { 46 //do something here 47 } 48 }
