Java 多線程基礎(十)interrupt()和線程終止方式

Java 多線程基礎(十)interrupt()和線程終止方式

一、interrupt() 介紹

interrupt() 定義在 Thread 類中,作用是中斷本線程

本線程中斷自己是被允許的;其它線程調用本線程的 interrupt() 方法時,會通過 checkAccess() 檢查權限。這有可能拋出 SecurityException 異常。
如果本線程是處於阻塞狀態:調用線程的 wait() , wait(long) 或 wait(long, int) 會讓它進入等待(阻塞)狀態,或者調用線程的 join(),join(long),join(long, int),sleep(long),sleep(long, int) 也會讓它進入阻塞狀態。若線程在阻塞狀態時,調用了它的 interrupt() 方法,那麼它的“中斷狀態”會被清除並且會收到一個 InterruptedException 異常。例如,線程通過 wait() 進入阻塞狀態,此時通過 interrupt() 中斷該線程;調用 interrupt() 會立即將線程的中斷標記設為 true,但是由於線程處於阻塞狀態,所以該“中斷標記”會立即被清除為 “false”,同時,會產生一個 InterruptedException 的異常
如果線程被阻塞在一個 Selector 選擇器中,那麼通過 interrupt() 中斷它時;線程的中斷標記會被設置為 true,並且它會立即從選擇操作中返回。
如果不屬於前面所說的情況,那麼通過 interrupt() 中斷線程時,它的中斷標記會被設置為 true。
中斷一個“已終止的線程”不會產生任何操作。

二、線程終止方式

Thread中的 stop() 和 suspend() 方法,由於固有的不安全性,已經建議不再使用!
下面,我先分別討論線程在“阻塞狀態”和“運行狀態”的終止方式,然後再總結出一個通用的方式。

(一)、終止處於“阻塞狀態”的線程.

通常,我們通過“中斷”方式終止處於“阻塞狀態”的線程
當線程由於被調用了 sleep(),,wait(),join() 等方法而進入阻塞狀態;若此時調用線程的 interrupt() 將線程的中斷標記設為 true。由於處於阻塞狀態,中斷標記會被清除,同時產生一個InterruptedException 異常。將 InterruptedException 放在適當的位置就能終止線程,形式如下:

public void run() {
    try {
        while (true) {
            // 執行業務
        }
    } catch (InterruptedException ie) {  
        // 由於產生InterruptedException異常,退出while(true)循環,線程終止!
    }
}

說明:

在while(true)中不斷的執行業務代碼,當線程處於阻塞狀態時,調用線程的 interrupt() 產生 InterruptedException 中斷。中斷的捕獲在 while(true) 之外,這樣就退出了 while(true) 循環!

注意:

對 InterruptedException 的捕獲務一般放在 while(true) 循環體的外面,這樣,在產生異常時就退出了 while(true) 循環。否則,InterruptedException 在 while(true) 循環體之內,就需要額外的添加退出處理。形式如下: 

public void run() {
    while (true) {
        try {
            // 執行任務...
        } catch (InterruptedException ie) {  
            // InterruptedException在while(true)循環體內。
            // 當線程產生了InterruptedException異常時,while(true)仍能繼續運行!需要手動退出
            break;
        }
    }
}

說明:

上面的 InterruptedException 異常的捕獲在 whle(true) 之內。當產生 InterruptedException 異常時,被 catch 處理之外,仍然在 while(true) 循環體內;要退出 while(true) 循環體,需要額外的執行退出while(true) 的操作。

(二)、終止處於“運行狀態”的線程

通常,我們通過“標記”方式終止處於“運行狀態”的線程。其中,包括“中斷標記”和“額外添加標記”。

1、通過“中斷標記”終止線程

public void run() {
    while (!isInterrupted()) {
        // 執行任務...
    }
}

說明:

isInterrupted() 是判斷線程的中斷標記是不是為 true。當線程處於運行狀態,並且我們需要終止它時;可以調用線程的 interrupt() 方法,使用線程的中斷標記為 true,即 isInterrupted() 會返回true。此時,就會退出while循環。
注意:interrupt() 並不會終止處於“運行狀態”的線程!它會將線程的中斷標記設為 true。

2、通過“額外添加標記”終止線程

private volatile boolean flag= true;
protected void stopTask() {
    flag = false;
}
public void run() {
    while (flag) {
        // 執行任務...
    }
}

說明:

線程中有一個 flag 標記,它的默認值是 true;並且我們提供 stopTask() 來設置 flag 標記。當我們需要終止該線程時,調用該線程的 stopTask() 方法就可以讓線程退出 while 循環。
注意:將 flag 定義為 volatile 類型,是為了保證 flag 的可見性。即其它線程通過 stopTask() 修改了 flag 之後,本線程能看到修改后的 flag 的值。

(三)、通過方式

綜合線程處於“阻塞狀態”和“運行狀態”的終止方式,比較通用的終止線程的形式如下:

public void run() {
    try {
        // 1. isInterrupted()保證,只要中斷標記為true就終止線程。
        while (!isInterrupted()) {
            // 執行任務...
        }
    } catch (InterruptedException ie) {  
        // 2. InterruptedException異常保證,當InterruptedException異常產生時,線程被終止。
    }
}
1、isInterrupted()保證,只要中斷標記為 true 就終止線程。
2、InterruptedException 異常保證,當 InterruptedException 異常產生時,線程被終止。

三、示例

public class InterruptTest {
    public static void main(String[] args) {
        try {
            Thread t1 = new MyThread("t1"); // 新建線程t1
            System.out.println(t1.getName() + "[" + t1.getState() + "] is new.");
            
            t1.start();// 啟動線程t1
            System.out.println(t1.getName() + "[" + t1.getState() + "] is started.");
            
            Thread.sleep(300);// 休眠300毫秒,然後主線程給t1發“中斷”指令,查看t1狀態
            t1.interrupt();
            System.out.println(t1.getName() + "[" + t1.getState() + "] is interrupted.");
            
            Thread.sleep(300);// 休眠300毫秒,然後查看t1狀態
            System.out.println(t1.getName() + "[" + t1.getState() + "] is interrupted now.");
        }catch(InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class MyThread extends Thread{
    public MyThread(String name) {
        super(name);
    }
    @Override
    public void run() {
        try {
            int i = 0;
            while(!isInterrupted()) {
                Thread.sleep(100);// 休眠100毫秒
                ++i;
                System.out.println(Thread.currentThread().getName() + "[" + this.getState() + "] loop " + i);
            }
        }catch(InterruptedException e) {
            System.out.println(Thread.currentThread().getName() + "[" + this.getState() + "] catch InterruptedException");
        }
    }
}
// 運行結果
t1 [ NEW ] is new.
t1 [ RUNNABLE ] is started.
t1 [ RUNNABLE ] loop 1
t1 [ RUNNABLE ] loop 2
t1 [ RUNNABLE ] loop 3
t1 [ RUNNABLE ] catch InterruptedException
t1 [ TERMINATED ] is interrupted.
t1 [ TERMINATED ] is interrupted now.

說明:

①、主線程 main 中通過 new MyThread(“t1”) 創建線程 t1,之後通過 t1.start() 啟動線程 t1。
②、t1 啟動之後,會不斷的檢查它的中斷標記,如果中斷標記為“false”;則休眠 100ms。
③、t1 休眠之後,會切換到主線程main;主線程再次運行時,會執行t1.interrupt()中斷線程t1。t1收到中斷指令之後,會將t1的中斷標記設置“false”,而且會拋出 InterruptedException 異常。在 t1 的 run() 方法中,是在循環體 while 之外捕獲的異常;因此循環被終止。

我們對上面的結果進行小小的修改,將run()方法中捕獲InterruptedException異常的代碼塊移到while循環體內。

public class InterruptTest {
    public static void main(String[] args) {
        try {
            Thread t1 = new MyThread("t1"); // 新建線程t1
            System.out.println(t1.getName() + " [ " + t1.getState() + " ] is new.");
            
            t1.start();// 啟動線程t1
            System.out.println(t1.getName() + " [ " + t1.getState() + " ] is started.");
            
            Thread.sleep(300);// 休眠300毫秒,然後主線程給t1發“中斷”指令,查看t1狀態
            t1.interrupt();
            System.out.println(t1.getName() + " [ " + t1.getState() + " ] is interrupted.");
            
            Thread.sleep(300);// 休眠300毫秒,然後查看t1狀態
            System.out.println(t1.getName() + " [ " + t1.getState() + " ] is interrupted now.");
        }catch(InterruptedException e) {
            e.printStackTrace();
        }
        
    }
}
class MyThread extends Thread{
    public MyThread(String name) {
        super(name);
    }
    @Override
    public void run() {
        int i = 0;
        while(!isInterrupted()) {
            try {
                Thread.sleep(100); // 休眠100ms
            } catch (InterruptedException ie) {  
                System.out.println(Thread.currentThread().getName() +" [ "+this.getState()+" ] catch InterruptedException.");  
            }
            i++;
            System.out.println(Thread.currentThread().getName()+" [ "+this.getState()+" ] loop " + i);  
        }
    }
}
// 運行結果
t1 [ NEW ] is new.
t1 [ RUNNABLE ] is started.
t1 [ RUNNABLE ] loop 1
t1 [ RUNNABLE ] loop 2
t1 [ TIMED_WAITING ] is interrupted.
t1 [ RUNNABLE ] catch InterruptedException.
t1 [ RUNNABLE ] loop 3
t1 [ RUNNABLE ] loop 4
t1 [ RUNNABLE ] loop 5
t1 [ RUNNABLE ] loop 6
t1 [ RUNNABLE ] is interrupted now.
t1 [ RUNNABLE ] loop 7
...... // 無限循環

說明:

程序進入了死循環了。

這是因為,t1在“等待(阻塞)狀態”時,被 interrupt() 中斷;此時,會清除中斷標記(即 isInterrupted() 會返回 false),而且會拋出 InterruptedException 異常(該異常在while循環體內被捕獲)。因此,t1理所當然的會進入死循環了。
解決該問題,需要我們在捕獲異常時,額外的進行退出 while 循環的處理。例如,在 MyThread 的 catch(InterruptedException) 中添加 break 或 return 就能解決該問題。

下面是通過“額外添加標記”的方式終止“狀態狀態”的線程的示例:

public class InterruptTest {
    public static void main(String[] args) {
        try {
            MyThread t1 = new MyThread("t1"); // 新建線程t1
            System.out.println(t1.getName() + " [ " + t1.getState() + " ] is new.");
            
            t1.start();// 啟動線程t1
            System.out.println(t1.getName() + " [ " + t1.getState() + " ] is started.");
            
            Thread.sleep(300);// 休眠300毫秒,然後主線程給t1發“中斷”指令,查看t1狀態
            t1.stopTask();
            System.out.println(t1.getName() + " [ " + t1.getState() + " ] is interrupted.");
            
            Thread.sleep(300);// 休眠300毫秒,然後查看t1狀態
            System.out.println(t1.getName() + " [ " + t1.getState() + " ] is interrupted now.");
        }catch(InterruptedException e) {
            e.printStackTrace();
        }
        
    }
}
class MyThread extends Thread{
    private volatile boolean flag = true;
    public void stopTask() {
        flag = false;
    }
    public MyThread(String name) {
        super(name);
    }
    @Override
    public void run() {
        synchronized (this) {
            int i = 0;
            while(flag) {
                try {
                    Thread.sleep(100); // 休眠100ms
                } catch (InterruptedException ie) {  
                    System.out.println(Thread.currentThread().getName() +" [ "+this.getState()+" ] catch InterruptedException.");  
                    break;
                }
                i++;
                System.out.println(Thread.currentThread().getName()+" [ "+this.getState()+" ] loop " + i);  
            }
        }
        
    }
}
// 運行結果
t1 [ NEW ] is new.
t1 [ RUNNABLE ] is started.
t1 [ RUNNABLE ] loop 1
t1 [ RUNNABLE ] loop 2
t1 [ RUNNABLE ] loop 3
t1 [ RUNNABLE ] is interrupted.
t1 [ TERMINATED ] is interrupted now.

四、interrupted() 和 isInterrupted()的區別

interrupted() 和 isInterrupted()都能夠用於檢測對象的“中斷標記”。
區別是,interrupted() 除了返回中斷標記之外,它還會清除中斷標記(即將中斷標記設為 false);而 isInterrupted() 僅僅返回中斷標記

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

聯合國示警:氣候變遷加劇阿拉伯地區衝突局勢

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

核外洩「鈾污染」超標1300倍 美國西屋工廠地板破8公分

摘錄自2018年7月26日東森新聞報導

美國南卡羅萊納州西屋公司(Westinghouse)驚傳核外洩,放射性鈾已經污染廠區下方的土壤,程度是一般土壤環境中鈾含量的約1300倍。據《美聯社》報導,核燃料生產廠的鋼筋水泥地板破洞約8公分,導致放射性鈾外洩。美國疾病控管及防治中心的資料顯示,若水中的鈾含量超標,可能造成飲用者腎臟受損。

美國聯邦核能規範委員會(Nuclear Regulatory Commission,NRC)已經證實此事。該廠位於南卡首府、最大城哥倫比亞市的南邊,放射性的鈾是用來製造核燃料棒。

西屋公司二年前曾因工廠防治空污裝置中的鈾累積過多,而關閉部分廠區。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

季節變化間顯現 科學家找到人為暖化的「指紋」

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

※教你寫出一流的銷售文案?

G20部長會議 矢言永續農業 消除饑餓

摘錄自2018年7月30日青年日報報導

G20農業部長會議28日於阿根廷布宜諾斯艾利斯落幕,會後各國農業部長發表聯合聲明,矢言「共同努力消除饑餓、促進永續農業,以實現未來糧食的不虞匱乏」。這將成為此屆G20的三大優先目標。

聲明且強調創新的重要性,並對「愈來愈常採取保護主義的非關稅貿易措施感到擔憂」;因為「農業發展、投資與貿易及引進改良技術,近數十年成為人類進步的驅動力,並改善全球數百萬人的生活條件」。G20農業部長因此鼓勵創新農業技術,提升農業生產力與永續性。

另重申土壤健康的重要性,認為其能強化農業在人類發展與資訊通訊技術(ICTs)中的角色,進而加強生產力、糧食安全與農業永續。同時呼籲減少食物損失與浪費,以增進糧食安全,減輕對氣候、水與土地資源造成壓力,並改善農夫、經銷商與家庭經濟的收入。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

新北清潔公司,居家、辦公、裝潢細清專業服務

※別再煩惱如何寫文案,掌握八大原則!

※教你寫出一流的銷售文案?

※超省錢租車方案

FB行銷專家,教你從零開始的技巧

電動車、太陽能福音 科學家找到可極速充電的材料

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

新北清潔公司,居家、辦公、裝潢細清專業服務

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

地球2017年體檢報告出爐 溫室氣體突破80萬年記錄

摘錄自2018年8月5日東森新聞報導

美國國家海洋暨大氣總署(NOAA)1日發布了2017年的氣候狀況報告,顯示地球的溫室氣體突破80萬年來的紀錄,這份報告由超過500名全球科學家共同研究,測量2017年的溫度、降水和天氣現象。美國氣象學會公報主編羅森菲爾德(Jeff Rosenfeld)說,這個報告就像地球的身體檢查一樣。

「每年都會檢查同樣的項目,這些數據可以讓我們了解長時間來看,什麼是正常狀況,什麼是異常」,羅森菲爾德說。根據這份長達300頁的報告,2017年地球表面的全球平均二氧化碳濃度是405ppm,比2016年高出2.2ppm,是近代大氣測量記錄和80萬年的冰芯紀錄中最高的。

報告指出,自1960年代以來,二氧化碳濃度已經成長近4倍,海平面高度也創下新高,平均每年上升1.2英吋(3.05公分),現在的海平面高度已經比1993年高約3英吋(7.62公分)。此外,2017年是有記錄以來最熱的非聖嬰年,巴基斯坦甚至在5月份時達到目前世界記錄的5月最高溫攝氏53.5度。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

數據為大貓洗污名 印度北方邦努力和虎豹當好鄰居

環境資訊中心綜合外電;范震華 編譯;賴慧玲 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

FB行銷專家,教你從零開始的技巧

Model S 第4次起火 經調查與車身或電池缺陷無關

據彭博社報導,11月發生在美國南加州的特斯拉Model S車庫起火事件有了新進展,調查人員們認為這次起火事故不是由於車身或電池缺陷引起的,不能被定性為特斯拉今年的第4起起火事故。

調查人員指出,該起火事故可能是由於充電系統過熱引起的,給車輛充電的電線品質上的缺陷可能是造成事故的原因。

由於這起事故與Model S本身無關,美國國家公路安全管理局(NHTSA)將調查重點放在今年秋天發生的三起起火事故上。目前所有事故中均無人員傷亡。特斯拉表示會對Model S的懸架系統進行調整,以避免類似事故的發生。

在田納西州和華盛頓州兩起車禍起火事故後,NHTSA上月對Model S電動車展開複查。第3起事故發生在墨西哥,駕駛當時高速撞上混凝土護欄,上述事故都未造成人員受傷。NHTSA尚未表明複查工作何時完成。

但德國交通監管當局本月已清除Model S安全瑕疵之慮,移除在德國召回這款電動車的可能性。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

福特CES展新款插電式電動車 利用太陽能板充電

據悉,全美第2大車廠福特汽車公司(Ford Motor)準備展示1款插電式混合動力電動車,這款車透過車頂太陽能板充電。C-Max Solar Energi將在7日起於拉斯維加斯登場的2014國際消費電子展(International Consumer Electronics Show)亮相。

C-Max純靠電力可行駛大約21英里(34公里),最遠行程620英里左右。C-Max的車頂配備SunPower公司300至350瓦的太陽能電池,預告未來可能生產不需插電的量產充電車。

這輛車的概念包括設置類似頂篷的停車棚,運用菲涅爾透鏡(Fresnel lenses)將陽光聚焦在這輛車,提高太陽能電池的效能。這款電動車還配有與充電站接合的標準充電器。

這款車由喬治亞理工學院(Georgia Institute of Technology)研發,可隨太陽的移動方向轉換位置。福特預估,該公司去年賣出超過8萬5000輛混合動力車及電動車。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案