一塊兒來學多線程-優雅關閉線程

Java中原來在Thread中提供了 stop()方法來終止線程,但這個方法是不安全的,因此通常不建議使用。文本將介紹兩種能夠優雅的終止線程的方式...java

第一種

在JAVA Java多線程模式》中有一種叫 Two-PhaseTermination(兩步終止)的模式能夠優雅的終止線程,這種模式採用了兩個步驟來終止線程,因此叫 兩步終止模式git

  • 先將執行標誌位 isShutdown 設爲 false,使工做中的線程轉變爲 終止處理中的狀態安全

  • 真正去執行終止操做,這樣的作法能夠保證線程的安全性、生命性和響應性。微信

  
    
  
  
  
   
   
            
   
   
  1. 多線程

  2. ide

  3. 測試

  4. flex

  5. this

  6. 編碼

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接收到關閉通知......打斷正在工做的線程......銷燬......
  • 安全性:不會在線程正在執行關鍵區域 --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源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索