Java中原來在Thread中提供了
stop()方法
來終止線程,但這個方法是不安全的,因此通常不建議使用。文本將介紹兩種能夠優雅的終止線程的方式...java
<!-- more -->git
在JAVA《Java多線程模式》
中有一種叫Two-Phase Termination(兩步終止)的模式
能夠優雅的終止線程,這種模式採用了兩個步驟來終止線程,因此叫兩步終止模式
。安全
isShutdown
設爲false
,使工做中的線程轉變爲終止處理
中的狀態class Worker extends Thread { private volatile boolean isShutdown = true; public void shutdown() { System.out.println("接收到關閉通知......"); this.isShutdown = false; interrupt(); } @Override public void run() { while (this.isShutdown) { System.out.println("正在工做:" + System.currentTimeMillis()); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("打斷正在工做的線程......"); } } System.out.println("銷燬......"); } } public class ThreadClose { public static void main(String[] args) throws InterruptedException { Worker worker = new Worker(); worker.start();//開始工做 Thread.sleep(3 * 1000); worker.shutdown();//優雅關閉 } }
運行日誌微信
正在工做:1505828036769 正在工做:1505828037770 正在工做:1505828038771 接收到關閉通知...... 打斷正在工做的線程...... 銷燬......
--Critical Section
的時候忽然結束掉shutdown()
中,會調用interrupt()
,保證即便線程處於sleep
或wait
狀態也能夠被當即終止isShutdown
設爲volatile
,能保證線程收到終止請求後,會盡快開始終止處理。存在的問題:針對沒有阻塞的狀況:設置標誌變量,讓線程正常天然死亡,和諧!,可是若是在調用shutdown
發生阻塞狀況呢?多線程
在 《多線程第一章》的時候,介紹過守護線程
的做用,那麼是否是能夠經過開啓守護線程
的方式去監聽ide
1.當工做結束就關閉主線程(主線程銷燬守護線程也會跟着一同銷燬)
2.若是任務長時間未完成,中止工做任務,減小開銷測試
1.定義主線程與發送的指令
2.在主線程run
方法中建立一個守護線程,用來執行咱們投遞的任務
3.前面已經介紹過join
的功能,它能夠阻塞主線程,等待子線程完成後主線程繼續執行
4.若是join
釋放後,發送完成指令this
private Thread executeService; private volatile boolean finished = false; public void execute(Runnable task) { executeService = new Thread(() -> { Thread runner = new Thread(task); runner.setDaemon(true); runner.start(); try { runner.join();//前面已經說過join與線程了 finished = true; } catch (InterruptedException e) { System.out.println("打斷正在工做的線程......"); } }); executeService.start(); }
5.建立listener(long mills)
,監聽工做狀況
6.監放任務是否完成,若是未完成監聽當前是否逾期,逾期打斷線程結束監聽編碼
public void listener(long mills) { System.out.println("開啓監聽......"); long currentTime = System.currentTimeMillis(); while (!finished) { if ((System.currentTimeMillis() - currentTime) >= mills) { System.out.println("工做耗時過長,開始打斷..."); executeService.interrupt();//打斷線程 break; } try { executeService.sleep(100L);//每隔100毫秒檢測一次 } catch (InterruptedException e) { e.printStackTrace(); } } }
7.測試線程
public static void main(String[] args) { WorkerService service = new WorkerService(); long start = System.currentTimeMillis(); service.execute(() -> { try { Thread.sleep(3 * 1000);// TODO 模擬加載數據 } catch (InterruptedException e) { e.printStackTrace(); } }); service.listener(4 * 1000); System.out.println("一共耗時:" + (System.currentTimeMillis() - start)); }
listener(4 * 1000) 的運行日誌,當任務完成會直接退出,並不會一直佔用
開啓監聽...... 一共耗時:3049
listener(2 * 1000) 的運行日誌,當任務超時直接打斷線程,減小資源佔用
開啓監聽...... 工做耗時過長,開始打斷... 一共耗時:2050 打斷正在工做的線程......
微信公衆號:battcn
(歡迎調戲)