Java中線程中斷停止的三種實現(xiàn)方法
對于線程的停止,通常情況下我們是不會去手動去停止的,而是等待線程自然運行至結(jié)束,但在實際開發(fā)中,很多情況中需要我們提前去手動來停止線程,比如程序中出現(xiàn)異常錯誤、使用者關(guān)閉程序等情況中。如果不能很好地停止線程那么可能會導(dǎo)致各種問題,所以正確的停止線程是非常的重要的,常見的中斷線程的方式有以下幾種:
1、方式一:使用 Thread 類的 stop() 方法來終止線程(廢棄):
Thread 類的 stop() 方法雖然可以終止線程,但該方法已被標(biāo)識為廢棄方法,原因是 stop() 方法太過暴力,即使線程只執(zhí)行一半,也會被強行終止,不能保證線程資源正確釋放,線程不安全,從而產(chǎn)生不可預(yù)料的結(jié)果,因此不提倡使用。
2、方式二:根據(jù) volatile 修飾的標(biāo)志位判斷線程是否需要中斷:
public static class ChangeObjectThread extends Thread { // 表示是否停止線程 private volatile boolean stopMe = true; public void stopMe() { stopMe = false; } @Override public void run() { while (!stopMe) { System.out.println("I'm running"); } } }
在上面的代碼里面,定義了一個標(biāo)記變量 stopMe,用于標(biāo)識線程是否需要退出,當(dāng) stopMe() 方法被調(diào)用時,stopMe 就會被賦值為 false,此時在代碼里面的 while(!stopMe) 就會檢測到這個改動,線程就退出了
3、方式三:通過 interrupt 中斷機(jī)制終止線程:
該方式的核心就是通過 interrupt() 方法設(shè)置線程的中斷標(biāo)志位,并通過 isInterrupt()/interrupted() 方法監(jiān)視并判斷中斷信號,當(dāng)線程檢測到為 true 時則說明接收到中斷信號,此時需要被中斷線程做相應(yīng)的處理。但如何去響應(yīng)這個中斷信號,被中斷線程有完全的自主權(quán),也就是中斷結(jié)果是死亡或是繼續(xù)運行,取決于這個被中斷線程本身的邏輯。
- Thread.interrupte():設(shè)置線程的中斷標(biāo)志位為 true,表示被其他線程進(jìn)行了中斷操作,但它不會像 stop() 方法那樣強制中斷正在運行的線程,僅僅起到通知被停止線程的作用;而被中斷線程,則需要通過監(jiān)視自身的標(biāo)志位是否被中斷來進(jìn)行響應(yīng),比如使用 isInterrupted() 或 interrupted() 方法來判斷是否被中斷;
- this.interrupted():測試當(dāng)前線程是否已經(jīng)中斷。如果連續(xù)兩次調(diào)用該方法,第一次返回 true,第二次返回false,因為 interrupted() 方法具有清除狀態(tài)的功能,它內(nèi)部實現(xiàn)是調(diào)用的當(dāng)前線程的 isInterrupted(),并且會重置當(dāng)前線程的中斷狀態(tài)。
- this.isInterrupted():測試線程是否已經(jīng)中斷,但是不會清除狀態(tài)標(biāo)識
3.1、使用 interrupt() + isInterrupted() 來中斷線程:
public static void main(String[] args) throws InterruptedException { Thread thread=new Thread(()->{ while (true){ System.out.println("t1線程還在運行......"); Thread current = Thread.currentThread(); boolean interrupted = current.isInterrupted(); //默認(rèn)值是false if (interrupted){ //如果外部調(diào)用中斷 那么會將該標(biāo)記改為true System.out.println("接受到中斷標(biāo)記....."+interrupted+"開始中斷線程....."); current.interrupted();//再次調(diào)用interrupted測試復(fù)位標(biāo)記 會重置清除標(biāo)記 注意是帶有ed 不是interrupt()方法 System.out.println("經(jīng)過interrupted復(fù)位后標(biāo)記為:"+current.isInterrupted()); break; } } },"t1"); thread.start(); thread.interrupt(); //設(shè)置線程中斷 } //運行結(jié)果 t1線程還在運行...... 接受到中斷標(biāo)記.....true開始中斷線程..... 經(jīng)過interrupted復(fù)位后標(biāo)記為:false
3.2、使用 interrupt() + InterruptedException 來中斷線程:
Thread thread2=new Thread(()->{ while (true){ System.out.println("t2線程還在運行......"); Thread current = Thread.currentThread(); if (current.isInterrupted()){ //判斷當(dāng)前線程是否中斷 System.out.println("接受到中斷標(biāo)記....."+Thread.currentThread().isInterrupted()); // break; } try { TimeUnit.SECONDS.sleep(5); //5s睡眠 } catch (InterruptedException e) { e.printStackTrace(); //因為拋出異常后會將線程標(biāo)記恢復(fù)為 默認(rèn)值false System.out.println("Thread.currentThread().isInterrupted() = " + Thread.currentThread().isInterrupted()); break; } } },"t2"); thread2.start(); thread2.interrupt(); } t2線程還在運行...... 接受到中斷標(biāo)記.....true Thread.currentThread().isInterrupted() = false java.lang.InterruptedException: sleep interrupted at java.base/java.lang.Thread.sleep(Native Method) at java.base/java.lang.Thread.sleep(Thread.java:339) at java.base/java.util.concurrent.TimeUnit.sleep(TimeUnit.java:446) at com.java.thread.TestInterrupt.lambda$main$0(TestInterrupt.java:40) at java.base/java.lang.Thread.run(Thread.java:834)
從上面的執(zhí)行結(jié)果可以證明,當(dāng)線程處于阻塞狀態(tài)(Sleep、wait、join)時,也是可以感受到中斷通知并拋出異常的,所以不用擔(dān)心長時間休眠中線程感受不到中斷了。
對于線程的停止,最正確最優(yōu)雅的方式就是通過 interrupt() 的方式來實現(xiàn),但 interrupt() 僅起到通知被停止線程的作用,對被停止的線程而言,它擁有完全的自主權(quán),既可以立即停止,也可以選擇一段時間后停止,也可以選擇不停止。比如拋出 InterruptedException 后,再次中斷設(shè)置,讓程序能后續(xù)繼續(xù)進(jìn)行終止操作;也比如線程在進(jìn)行 IO 操作時,比如寫文件操作,這時接收到終止線程的信號,那么它不會立馬停止,而是根據(jù)自身業(yè)務(wù)來判斷該如何處理,是將整個文件寫入成功后再停止還是不停止都取決于被通知線程的處理,因為如果立馬終止線程就可能造成數(shù)據(jù)的不完整性,這并不是業(yè)務(wù)所不希望的結(jié)果。那么可能很多讀者會疑惑,既然這樣那存在的意義有什么呢,其實是因為對于 Java 而言,就是期望程序之間是能夠相互通知、協(xié)作的管理線程
到此這篇關(guān)于Java中線程中斷停止的三種實現(xiàn)方法的文章就介紹到這了,更多相關(guān)Java 線程中斷停止內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java調(diào)用Python腳本傳遞數(shù)據(jù)并返回計算結(jié)果
實際工程項目中可能會用到Java和python兩種語言結(jié)合進(jìn)行,這樣就會涉及到一個問題,Java如何調(diào)用Python腳本,感興趣的可以了解一下2021-05-05java代碼獲取jenkins數(shù)據(jù),構(gòu)建歷史等信息方式
這篇文章主要介紹了java代碼獲取jenkins數(shù)據(jù),構(gòu)建歷史等信息方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05Java兩種動態(tài)代理JDK動態(tài)代理和CGLIB動態(tài)代理詳解
這篇文章主要介紹了Java兩種動態(tài)代理JDK動態(tài)代理和CGLIB動態(tài)代理詳解,代理模式是23種設(shè)計模式的一種,他是指一個對象A通過持有另一個對象B,可以具有B同樣的行為的模式,為了對外開放協(xié)議,B往往實現(xiàn)了一個接口,A也會去實現(xiàn)接口,需要的朋友可以參考下2023-11-11