Java中原來在Thread中提供了
stop()方法
來終止線程,但這個方法是不安全的,因此通常不建議使用。文本將介紹兩種能夠優雅的終止線程的方式...java
第一種
在JAVA 《Java多線程模式》
中有一種叫 Two-PhaseTermination(兩步終止)的模式
能夠優雅的終止線程,這種模式採用了兩個步驟來終止線程,因此叫 兩步終止模式
。git
先將執行標誌位
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();//優雅關閉 }}
多線程
ide
測試
flex
this
編碼
運行日誌
正在工做:1505828036769正在工做:1505828037770正在工做:1505828038771接收到關閉通知......打斷正在工做的線程......銷燬......
安全性:不會在線程正在執行關鍵區域
--CriticalSection
的時候忽然結束掉生命性:必定會進行終止處理,
shutdown()
中,會調用interrupt()
,保證即便線程處於sleep
或wait
狀態也能夠被當即終止響應性:將
isShutdown
設爲volatile
,能保證線程收到終止請求後,會盡快開始終止處理。
存在的問題:針對沒有阻塞的狀況:設置標誌變量,讓線程正常天然死亡,和諧!,可是若是在調用 shutdown
發生阻塞狀況呢?
第二種
在 《多線程第一章》的時候,介紹過 守護線程
的做用,那麼是否是能夠經過開啓 守護線程
的方式去監聽
功能
1.當工做結束就關閉主線程(主線程銷燬守護線程也會跟着一同銷燬) 2.若是任務長時間未完成,中止工做任務,減小開銷
編碼
1.定義主線程與發送的指令 2.在主線程 run
方法中建立一個守護線程,用來執行咱們投遞的任務 3.前面已經介紹過 join
的功能,它能夠阻塞主線程,等待子線程完成後主線程繼續執行 4.若是 join
釋放後,發送完成指令
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(longmills)
,監聽工做狀況 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
(歡迎調戲)
全文代碼:https://gitee.com/battcn/battcn-concurent/tree/master/Chapter1-1/battcn-thread/src/main/java/com/battcn/chapter4
我的QQ:1837307557
本文分享自微信公衆號 - battcn(battcn)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。