java 中斷線程的幾種方式 interrupt()詳解
中斷
中斷(Interrupt)一個(gè)線程意味著在該線程完成任務(wù)之前停止其正在進(jìn)行的一切,有效地中止其當(dāng)前的操作。線程是死亡、還是等待新的任務(wù)或是繼續(xù)運(yùn)行至下一步,就取決于這個(gè)程序。雖然初次看來(lái)它可能顯得簡(jiǎn)單,但是,你必須進(jìn)行一些預(yù)警以實(shí)現(xiàn)期望的結(jié)果。你最好還是牢記以下的幾點(diǎn)告誡。
首先,忘掉Thread.stop方法。雖然它確實(shí)停止了一個(gè)正在運(yùn)行的線程,然而,這種方法是不安全也是不受提倡的,這意味著,在未來(lái)的JAVA版本中,它將不復(fù)存在。
如何安全的結(jié)束一個(gè)正在運(yùn)行的線程
Thread類相關(guān)的方法
java.lang.Thread
類包含了一些常用的方法,如:start(), stop(), stop(Throwable) ,suspend(), destroy() ,resume()。通過(guò)這些方法,我們可以對(duì)線程進(jìn)行方便的操作,但是這些方法中,只有start()
方法得到了保留。
在JDK幫助文檔以及Sun公司的一篇文章《Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?》
中都講解了舍棄這些方法的原因。
簡(jiǎn)單來(lái)說(shuō)是因?yàn)椋菏褂胹top方法雖然可以強(qiáng)行終止
正在運(yùn)行或掛起的線程,但使用stop方法是很危險(xiǎn)
的,就象突然關(guān)閉計(jì)算機(jī)電源,而不是按正常程序關(guān)機(jī)一樣,可能會(huì)產(chǎn)生不可預(yù)料的結(jié)果,因此,并不推薦使用stop方法來(lái)終止線程。
那么,我們究竟應(yīng)該如何停止線程呢?
1、任務(wù)中一般都會(huì)有循環(huán)結(jié)構(gòu),只要用一個(gè)標(biāo)記控制住循環(huán),就可以結(jié)束任務(wù)。
2、如果線程處于了凍結(jié)狀態(tài)
,無(wú)法讀取標(biāo)記,此時(shí)可以使用interrupt()
方法將線程從凍結(jié)狀態(tài)強(qiáng)制恢復(fù)到運(yùn)行狀態(tài)中
來(lái),讓線程具備CPU的執(zhí)行資格。
(一):使用退出標(biāo)志
當(dāng)run方法執(zhí)行完后,線程就會(huì)退出。但有時(shí)run方法是永遠(yuǎn)不會(huì)結(jié)束的,如在服務(wù)端程序中使用線程進(jìn)行監(jiān)聽(tīng)客戶端請(qǐng)求,或是其他的需要循環(huán)處理的任務(wù)。
在這種情況下,一般是將這些任務(wù)放在一個(gè)循環(huán)中,如while循環(huán)。如果想使while循環(huán)在某一特定條件下退出,最直接的方法就是設(shè)一個(gè)boolean類型的標(biāo)志,并通過(guò)設(shè)置這個(gè)標(biāo)志為true或false來(lái)控制while循環(huán)是否退出。
public class test1 { public static volatile boolean exit =false; //退出標(biāo)志 public static void main(String[] args) { new Thread() { public void run() { System.out.println("線程啟動(dòng)了"); while (!exit) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("線程結(jié)束了"); } }.start(); try { Thread.sleep(1000 * 5); } catch (InterruptedException e) { e.printStackTrace(); } exit = true;//5秒后更改退出標(biāo)志的值,沒(méi)有這段代碼,線程就一直不能停止 } }
(二):使用 interrupt 方法
Thread.interrupt()方法: 作用是中斷線程。將會(huì)設(shè)置該線程的中斷狀態(tài)位,即設(shè)置為true,中斷的結(jié)果線程是死亡、還是等待新的任務(wù)或是繼續(xù)運(yùn)行至下一步,就取決于這個(gè)程序本身。線程會(huì)不時(shí)地檢測(cè)這個(gè)中斷標(biāo)示位,以判斷線程是否應(yīng)該被中斷(中斷標(biāo)示值是否為true)。它并不像stop方法那樣會(huì)中斷一個(gè)正在運(yùn)行的線程
interrupt()方法只是改變中斷狀態(tài),不會(huì)中斷一個(gè)正在運(yùn)行的線程。需要用戶自己去監(jiān)視線程的狀態(tài)為并做處理。支持線程中斷的方法(也就是線程中斷后會(huì)拋出interruptedException的方法)就是在監(jiān)視線程的中斷狀態(tài),一旦線程的中斷狀態(tài)被置為“中斷狀態(tài)”,就會(huì)拋出中斷異常。這一方法實(shí)際完成的是,給受阻塞的線程發(fā)出一個(gè)中斷信號(hào),這樣受阻線程檢查到中斷標(biāo)識(shí),就得以退出阻塞的狀態(tài)。
更確切的說(shuō),如果線程被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞,此時(shí)調(diào)用該線程的interrupt()方法,那么該線程將拋出一個(gè) InterruptedException中斷異常(該線程必須事先預(yù)備好處理此異常),從而提早地終結(jié)被阻塞狀態(tài)。如果線程沒(méi)有被阻塞,這時(shí)調(diào)用 interrupt()將不起作用,直到執(zhí)行到wait(),sleep(),join()時(shí),才馬上會(huì)拋出 InterruptedException。
使用 interrupt() + InterruptedException來(lái)中斷線程
線程處于阻塞狀態(tài),如Thread.sleep、wait、IO阻塞
等情況時(shí),調(diào)用interrupt方法后,sleep等方法將會(huì)拋出一個(gè)InterruptedException:
public static void main(String[] args) { Thread thread = new Thread() { public void run() { System.out.println("線程啟動(dòng)了"); try { Thread.sleep(1000 * 100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("線程結(jié)束了"); } }; thread.start(); try { Thread.sleep(1000 * 5); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt();//作用是:在線程阻塞時(shí)拋出一個(gè)中斷信號(hào),這樣線程就得以退出阻塞的狀態(tài) }
使用 interrupt() + isInterrupted()來(lái)中斷線程
this.interrupted():測(cè)試當(dāng)前線程是否已經(jīng)中斷(靜態(tài)方法)。如果連續(xù)調(diào)用該方法,則第二次調(diào)用將返回false。在api文檔中說(shuō)明interrupted()方法具有清除狀態(tài)的功能。執(zhí)行后具有將狀態(tài)標(biāo)識(shí)清除為false的功能。
this.isInterrupted():測(cè)試線程是否已經(jīng)中斷,但是不能清除狀態(tài)標(biāo)識(shí)。
public static void main(String[] args) { Thread thread = new Thread() { public void run() { System.out.println("線程啟動(dòng)了"); while (!isInterrupted()) { System.out.println(isInterrupted());//調(diào)用 interrupt 之后為true } System.out.println("線程結(jié)束了"); } }; thread.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); System.out.println("線程是否被中斷:" + thread.isInterrupted());//true }
。。。。。。。。。。
來(lái)一個(gè)綜合的例子:
public class test1 { static volatile boolean flag = true; public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("開(kāi)始休眠"); try { Thread.sleep(100 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("結(jié)束休眠,開(kāi)始死循環(huán)"); while (flag) { } System.out.println("------------------子線程結(jié)束------------------"); } }); thread.start(); Scanner scanner = new Scanner(System.in); System.out.println("輸入1拋出一個(gè)中斷異常,輸入2修改循環(huán)標(biāo)志位,輸入3判斷線程是否阻塞,輸入其他結(jié)束Scanner\n"); while (scanner.hasNext()) { String text = scanner.next(); System.out.println("你輸入了:" + text + "\n"); if ("1".equals(text)) { thread.interrupt(); } else if ("2".equals(text)) { flag = false; //如果不設(shè)為false,主線程結(jié)束后子線程仍在運(yùn)行 } else if ("3".equals(text)) { System.out.println(thread.isInterrupted()); } else { scanner.close(); break; } } System.out.println("------------------主線程結(jié)束------------------"); } }
不能結(jié)束的情況
注意下面這種是根本不能結(jié)束的情況!
public class Test { public static void main(String[] args) { Thread thread = new Thread() { public void run() { System.out.println("線程啟動(dòng)了"); while (true) {//對(duì)于這種情況,即使線程調(diào)用了intentrupt()方法并且isInterrupted(),但線程還是會(huì)繼續(xù)運(yùn)行,根本停不下來(lái)! System.out.println(isInterrupted());//調(diào)用interrupt之后為true } } }; thread.start(); thread.interrupt();//注意,此方法不會(huì)中斷一個(gè)正在運(yùn)行的線程,它的作用是:在線程受到阻塞時(shí)拋出一個(gè)中斷信號(hào),這樣線程就得以退出阻塞的狀態(tài) while (true) { System.out.println("是否isInterrupted:" + thread.isInterrupted());//true } } }
關(guān)于interrupted()和isInterrupted()方法的注意事項(xiàng)說(shuō)明
interrupted()是靜態(tài)方法:內(nèi)部實(shí)現(xiàn)是調(diào)用的當(dāng)前線程的isInterrupted(),并且會(huì)重置當(dāng)前線程的中斷狀態(tài)。
測(cè)試當(dāng)前線程是否已經(jīng)中斷(靜態(tài)方法)。返回的是上一次的中斷狀態(tài),并且會(huì)清除該狀態(tài),所以連續(xù)調(diào)用兩次,第一次返回true,第二次返回false。
isInterrupted()是實(shí)例方法,是調(diào)用該方法的對(duì)象所表示的那個(gè)線程的isInterrupted(),不會(huì)重置當(dāng)前線程的中斷狀態(tài)
測(cè)試線程當(dāng)前是否已經(jīng)中斷,但是不能清除狀態(tài)標(biāo)識(shí)。
測(cè)試方法驗(yàn)證:
1:
第一個(gè)紅框中斷的線程是我們自己創(chuàng)建的thread線程,我調(diào)用的interrupted(),由上面源碼可知是判斷當(dāng)前線程的中斷狀態(tài),當(dāng)前線程是main線程,我根本沒(méi)有中斷過(guò)main線程,所以2次調(diào)用均返回“false”
2:
第一個(gè)紅框中斷的線程是當(dāng)前線程(main線程),我調(diào)用的interrupted(),由上面源碼可知是判斷當(dāng)前線程的中斷狀態(tài),當(dāng)前線程是main線程,所以第1次調(diào)用結(jié)果返回“true”,因?yàn)槲掖_實(shí)中斷了main線程
由源碼可知interrupted()調(diào)用的是isInterrupted(),并會(huì)重置中斷狀態(tài),所以第一次調(diào)用之后把中斷狀態(tài)給重置了,從中斷狀態(tài)重置為非中斷狀態(tài),所以第2次調(diào)用的結(jié)果返回“false”
3:
第一個(gè)紅框中斷的線程是我們自己創(chuàng)建的thread線程,我調(diào)用的isInterrupted(),由上面源碼可知是判斷執(zhí)行該方法的對(duì)象所表示線程的中斷狀態(tài),也就是thread引用所表示的線程的中斷狀態(tài),所以第1次調(diào)用結(jié)果返回“true”,
由源碼可知isInterrupted()不會(huì)重置中斷狀態(tài),所以第一次調(diào)用之后沒(méi)有把中斷狀態(tài)給重置(從中斷狀態(tài)重置為非中斷狀態(tài)),所以第2次調(diào)用的結(jié)果還返回“true”
到此這篇關(guān)于java 中斷線程的幾種方式 interrupt()的文章就介紹到這了,更多相關(guān)java 中斷線程interrupt()內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中StringUtils工具類的一些用法實(shí)例
這篇文章主要介紹了Java中StringUtils工具類的一些用法實(shí)例,本文著重講解了isEmpty和isBlank方法的使用,另外也講解了trim、strip等方法的使用實(shí)例,需要的朋友可以參考下2015-06-06Java案例使用比較排序器comparator實(shí)現(xiàn)成績(jī)排序
這篇文章主要介紹了Java案例使用比較排序器comparator實(shí)現(xiàn)成績(jī)排序,主要通過(guò)案例用TreeSet集合存儲(chǔ)多個(gè)學(xué)生信息,并遍歷該集合,要按照總分從高到低進(jìn)行排序,下文介紹需要的朋友可以參考一下2022-04-04SpringBoot整合websocket實(shí)現(xiàn)即時(shí)通信聊天
這篇文章主要介紹了SpringBoot整合websocket實(shí)現(xiàn)即時(shí)通信聊天,實(shí)時(shí)通信是一個(gè)實(shí)時(shí)通信系統(tǒng),允許兩人或多人使用網(wǎng)絡(luò)實(shí)時(shí)的傳遞文字消息、文件、語(yǔ)音與視頻交流,需要的朋友可以參考下2022-05-05詳解SpringBoot如何創(chuàng)建自定義Starter
Spring Boot的自動(dòng)配置機(jī)制為開(kāi)發(fā)人員提供了一種輕松集成和配置各種功能的便捷方式,本文將深入探討在Spring Boot中如何創(chuàng)建自定義Starter,為構(gòu)建模塊化且易維護(hù)的應(yīng)用提供有力的支持,需要的朋友可以參考下2024-02-02java 利用java反射機(jī)制動(dòng)態(tài)加載類的簡(jiǎn)單實(shí)現(xiàn)
下面小編就為大家?guī)?lái)一篇java 利用java反射機(jī)制動(dòng)態(tài)加載類的簡(jiǎn)單實(shí)現(xiàn)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-09-09Java EE項(xiàng)目中的異常處理總結(jié)(一篇不得不看的文章)
什么是異常?運(yùn)行時(shí)發(fā)生的可被捕獲和處理的錯(cuò)誤。這篇文章主要介紹了Java EE項(xiàng)目中的異常處理總結(jié),有需要的可以了解一下。2016-11-11