Java中線程中斷停止的三種實(shí)現(xiàn)方法
對(duì)于線程的停止,通常情況下我們是不會(huì)去手動(dòng)去停止的,而是等待線程自然運(yùn)行至結(jié)束,但在實(shí)際開發(fā)中,很多情況中需要我們提前去手動(dòng)來(lái)停止線程,比如程序中出現(xiàn)異常錯(cuò)誤、使用者關(guān)閉程序等情況中。如果不能很好地停止線程那么可能會(huì)導(dǎo)致各種問(wèn)題,所以正確的停止線程是非常的重要的,常見(jiàn)的中斷線程的方式有以下幾種:
1、方式一:使用 Thread 類的 stop() 方法來(lái)終止線程(廢棄):
Thread 類的 stop() 方法雖然可以終止線程,但該方法已被標(biāo)識(shí)為廢棄方法,原因是 stop() 方法太過(guò)暴力,即使線程只執(zhí)行一半,也會(huì)被強(qiáng)行終止,不能保證線程資源正確釋放,線程不安全,從而產(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"); } } }
在上面的代碼里面,定義了一個(gè)標(biāo)記變量 stopMe,用于標(biāo)識(shí)線程是否需要退出,當(dāng) stopMe() 方法被調(diào)用時(shí),stopMe 就會(huì)被賦值為 false,此時(shí)在代碼里面的 while(!stopMe) 就會(huì)檢測(cè)到這個(gè)改動(dòng),線程就退出了
3、方式三:通過(guò) interrupt 中斷機(jī)制終止線程:
該方式的核心就是通過(guò) interrupt() 方法設(shè)置線程的中斷標(biāo)志位,并通過(guò) isInterrupt()/interrupted() 方法監(jiān)視并判斷中斷信號(hào),當(dāng)線程檢測(cè)到為 true 時(shí)則說(shuō)明接收到中斷信號(hào),此時(shí)需要被中斷線程做相應(yīng)的處理。但如何去響應(yīng)這個(gè)中斷信號(hào),被中斷線程有完全的自主權(quán),也就是中斷結(jié)果是死亡或是繼續(xù)運(yùn)行,取決于這個(gè)被中斷線程本身的邏輯。
- Thread.interrupte():設(shè)置線程的中斷標(biāo)志位為 true,表示被其他線程進(jìn)行了中斷操作,但它不會(huì)像 stop() 方法那樣強(qiáng)制中斷正在運(yùn)行的線程,僅僅起到通知被停止線程的作用;而被中斷線程,則需要通過(guò)監(jiān)視自身的標(biāo)志位是否被中斷來(lái)進(jìn)行響應(yīng),比如使用 isInterrupted() 或 interrupted() 方法來(lái)判斷是否被中斷;
- this.interrupted():測(cè)試當(dāng)前線程是否已經(jīng)中斷。如果連續(xù)兩次調(diào)用該方法,第一次返回 true,第二次返回false,因?yàn)?interrupted() 方法具有清除狀態(tài)的功能,它內(nèi)部實(shí)現(xiàn)是調(diào)用的當(dāng)前線程的 isInterrupted(),并且會(huì)重置當(dāng)前線程的中斷狀態(tài)。
- this.isInterrupted():測(cè)試線程是否已經(jīng)中斷,但是不會(huì)清除狀態(tài)標(biāo)識(shí)
3.1、使用 interrupt() + isInterrupted() 來(lái)中斷線程:
public static void main(String[] args) throws InterruptedException { Thread thread=new Thread(()->{ while (true){ System.out.println("t1線程還在運(yùn)行......"); Thread current = Thread.currentThread(); boolean interrupted = current.isInterrupted(); //默認(rèn)值是false if (interrupted){ //如果外部調(diào)用中斷 那么會(huì)將該標(biāo)記改為true System.out.println("接受到中斷標(biāo)記....."+interrupted+"開始中斷線程....."); current.interrupted();//再次調(diào)用interrupted測(cè)試復(fù)位標(biāo)記 會(huì)重置清除標(biāo)記 注意是帶有ed 不是interrupt()方法 System.out.println("經(jīng)過(guò)interrupted復(fù)位后標(biāo)記為:"+current.isInterrupted()); break; } } },"t1"); thread.start(); thread.interrupt(); //設(shè)置線程中斷 } //運(yùn)行結(jié)果 t1線程還在運(yùn)行...... 接受到中斷標(biāo)記.....true開始中斷線程..... 經(jīng)過(guò)interrupted復(fù)位后標(biāo)記為:false
3.2、使用 interrupt() + InterruptedException 來(lái)中斷線程:
Thread thread2=new Thread(()->{ while (true){ System.out.println("t2線程還在運(yùn)行......"); 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(); //因?yàn)閽伋霎惓:髸?huì)將線程標(biāo)記恢復(fù)為 默認(rèn)值false System.out.println("Thread.currentThread().isInterrupted() = " + Thread.currentThread().isInterrupted()); break; } } },"t2"); thread2.start(); thread2.interrupt(); } t2線程還在運(yùn)行...... 接受到中斷標(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)時(shí),也是可以感受到中斷通知并拋出異常的,所以不用擔(dān)心長(zhǎng)時(shí)間休眠中線程感受不到中斷了。
對(duì)于線程的停止,最正確最優(yōu)雅的方式就是通過(guò) interrupt() 的方式來(lái)實(shí)現(xiàn),但 interrupt() 僅起到通知被停止線程的作用,對(duì)被停止的線程而言,它擁有完全的自主權(quán),既可以立即停止,也可以選擇一段時(shí)間后停止,也可以選擇不停止。比如拋出 InterruptedException 后,再次中斷設(shè)置,讓程序能后續(xù)繼續(xù)進(jìn)行終止操作;也比如線程在進(jìn)行 IO 操作時(shí),比如寫文件操作,這時(shí)接收到終止線程的信號(hào),那么它不會(huì)立馬停止,而是根據(jù)自身業(yè)務(wù)來(lái)判斷該如何處理,是將整個(gè)文件寫入成功后再停止還是不停止都取決于被通知線程的處理,因?yàn)槿绻ⅠR終止線程就可能造成數(shù)據(jù)的不完整性,這并不是業(yè)務(wù)所不希望的結(jié)果。那么可能很多讀者會(huì)疑惑,既然這樣那存在的意義有什么呢,其實(shí)是因?yàn)閷?duì)于 Java 而言,就是期望程序之間是能夠相互通知、協(xié)作的管理線程
到此這篇關(guān)于Java中線程中斷停止的三種實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)Java 線程中斷停止內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java調(diào)用Python腳本傳遞數(shù)據(jù)并返回計(jì)算結(jié)果
實(shí)際工程項(xiàng)目中可能會(huì)用到Java和python兩種語(yǔ)言結(jié)合進(jìn)行,這樣就會(huì)涉及到一個(gè)問(wèn)題,Java如何調(diào)用Python腳本,感興趣的可以了解一下2021-05-05使用Java增刪改查數(shù)據(jù)庫(kù)的操作方法
這篇文章主要介紹了使用Java增刪改查數(shù)據(jù)庫(kù)的操作方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-12-12java代碼獲取jenkins數(shù)據(jù),構(gòu)建歷史等信息方式
這篇文章主要介紹了java代碼獲取jenkins數(shù)據(jù),構(gòu)建歷史等信息方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-05-05javaweb圖書商城設(shè)計(jì)之用戶模塊(1)
這篇文章主要介紹了javaweb圖書商城設(shè)計(jì)之用戶模塊的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11Springboot靜態(tài)資源的訪問(wèn)方法介紹
最近在做SpringBoot項(xiàng)目的時(shí)候遇到了“白頁(yè)”問(wèn)題,通過(guò)查資料對(duì)SpringBoot訪問(wèn)靜態(tài)資源做了總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08Java兩種動(dòng)態(tài)代理JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理詳解
這篇文章主要介紹了Java兩種動(dòng)態(tài)代理JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理詳解,代理模式是23種設(shè)計(jì)模式的一種,他是指一個(gè)對(duì)象A通過(guò)持有另一個(gè)對(duì)象B,可以具有B同樣的行為的模式,為了對(duì)外開放協(xié)議,B往往實(shí)現(xiàn)了一個(gè)接口,A也會(huì)去實(shí)現(xiàn)接口,需要的朋友可以參考下2023-11-11