您好,登錄后才能下訂單哦!
本篇內容主要講解“java中斷線程有哪幾種方式”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“java中斷線程有哪幾種方式”吧!
中斷(Interrupt)一個線程意味著在該線程完成任務之前停止其正在進行的一切,有效地中止其當前的操作。線程是死亡、還是等待新的任務或是繼續運行至下一步,就取決于這個程序。雖然初次看來它可能顯得簡單,但是,你必須進行一些預警以實現期望的結果。你最好還是牢記以下的幾點告誡。
首先,忘掉Thread.stop方法。雖然它確實停止了一個正在運行的線程,然而,這種方法是不安全也是不受提倡的,這意味著,在未來的JAVA版本中,它將不復存在。
Thread類相關的方法
java.lang.Thread
類包含了一些常用的方法,如:start(), stop(), stop(Throwable) ,suspend(), destroy() ,resume()。通過這些方法,我們可以對線程進行方便的操作,但是這些方法中,只有start()
方法得到了保留。
在JDK幫助文檔以及Sun公司的一篇文章《Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?》
中都講解了舍棄這些方法的原因。
簡單來說是因為:使用stop方法雖然可以強行終止
正在運行或掛起的線程,但使用stop方法是很危險
的,就象突然關閉計算機電源,而不是按正常程序關機一樣,可能會產生不可預料的結果,因此,并不推薦使用stop方法來終止線程。
那么,我們究竟應該如何停止線程呢?
1、任務中一般都會有循環結構,只要用一個標記控制住循環,就可以結束任務。
2、如果線程處于了凍結狀態
,無法讀取標記,此時可以使用interrupt()
方法將線程從凍結狀態強制恢復到運行狀態中
來,讓線程具備CPU的執行資格。
(一):使用退出標志
當run方法執行完后,線程就會退出。但有時run方法是永遠不會結束的,如在服務端程序中使用線程進行監聽客戶端請求,或是其他的需要循環處理的任務。
在這種情況下,一般是將這些任務放在一個循環中,如while循環。如果想使while循環在某一特定條件下退出,最直接的方法就是設一個boolean類型的標志,并通過設置這個標志為true或false來控制while循環是否退出。
public class test1 { public static volatile boolean exit =false; //退出標志 public static void main(String[] args) { new Thread() { public void run() { System.out.println("線程啟動了"); while (!exit) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("線程結束了"); } }.start(); try { Thread.sleep(1000 * 5); } catch (InterruptedException e) { e.printStackTrace(); } exit = true;//5秒后更改退出標志的值,沒有這段代碼,線程就一直不能停止 } }
(二):使用 interrupt 方法
Thread.interrupt()方法: 作用是中斷線程。將會設置該線程的中斷狀態位,即設置為true,中斷的結果線程是死亡、還是等待新的任務或是繼續運行至下一步,就取決于這個程序本身。線程會不時地檢測這個中斷標示位,以判斷線程是否應該被中斷(中斷標示值是否為true)。它并不像stop方法那樣會中斷一個正在運行的線程
interrupt()方法只是改變中斷狀態,不會中斷一個正在運行的線程。需要用戶自己去監視線程的狀態為并做處理。支持線程中斷的方法(也就是線程中斷后會拋出interruptedException的方法)就是在監視線程的中斷狀態,一旦線程的中斷狀態被置為“中斷狀態”,就會拋出中斷異常。這一方法實際完成的是,給受阻塞的線程發出一個中斷信號,這樣受阻線程檢查到中斷標識,就得以退出阻塞的狀態。
更確切的說,如果線程被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞,此時調用該線程的interrupt()方法,那么該線程將拋出一個 InterruptedException中斷異常(該線程必須事先預備好處理此異常),從而提早地終結被阻塞狀態。如果線程沒有被阻塞,這時調用 interrupt()將不起作用,直到執行到wait(),sleep(),join()時,才馬上會拋出 InterruptedException。
線程處于阻塞狀態,如Thread.sleep、wait、IO阻塞
等情況時,調用interrupt方法后,sleep等方法將會拋出一個InterruptedException:
public static void main(String[] args) { Thread thread = new Thread() { public void run() { System.out.println("線程啟動了"); try { Thread.sleep(1000 * 100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("線程結束了"); } }; thread.start(); try { Thread.sleep(1000 * 5); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt();//作用是:在線程阻塞時拋出一個中斷信號,這樣線程就得以退出阻塞的狀態 }
使用 interrupt() + isInterrupted()來中斷線程
this.interrupted():測試當前線程是否已經中斷(靜態方法)。如果連續調用該方法,則第二次調用將返回false。在api文檔中說明interrupted()方法具有清除狀態的功能。執行后具有將狀態標識清除為false的功能。
this.isInterrupted():測試線程是否已經中斷,但是不能清除狀態標識。
public static void main(String[] args) { Thread thread = new Thread() { public void run() { System.out.println("線程啟動了"); while (!isInterrupted()) { System.out.println(isInterrupted());//調用 interrupt 之后為true } System.out.println("線程結束了"); } }; thread.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); System.out.println("線程是否被中斷:" + thread.isInterrupted());//true }
。。。。。。。。。。
來一個綜合的例子:
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("開始休眠"); try { Thread.sleep(100 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("結束休眠,開始死循環"); while (flag) { } System.out.println("------------------子線程結束------------------"); } }); thread.start(); Scanner scanner = new Scanner(System.in); System.out.println("輸入1拋出一個中斷異常,輸入2修改循環標志位,輸入3判斷線程是否阻塞,輸入其他結束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; //如果不設為false,主線程結束后子線程仍在運行 } else if ("3".equals(text)) { System.out.println(thread.isInterrupted()); } else { scanner.close(); break; } } System.out.println("------------------主線程結束------------------"); } }
不能結束的情況
注意下面這種是根本不能結束的情況!
public class Test { public static void main(String[] args) { Thread thread = new Thread() { public void run() { System.out.println("線程啟動了"); while (true) {//對于這種情況,即使線程調用了intentrupt()方法并且isInterrupted(),但線程還是會繼續運行,根本停不下來! System.out.println(isInterrupted());//調用interrupt之后為true } } }; thread.start(); thread.interrupt();//注意,此方法不會中斷一個正在運行的線程,它的作用是:在線程受到阻塞時拋出一個中斷信號,這樣線程就得以退出阻塞的狀態 while (true) { System.out.println("是否isInterrupted:" + thread.isInterrupted());//true } } }
關于interrupted()和isInterrupted()方法的注意事項說明
interrupted()是靜態方法:內部實現是調用的當前線程的isInterrupted(),并且會重置當前線程的中斷狀態。
測試當前線程是否已經中斷(靜態方法)。返回的是上一次的中斷狀態,并且會清除該狀態,所以連續調用兩次,第一次返回true,第二次返回false。
isInterrupted()是實例方法,是調用該方法的對象所表示的那個線程的isInterrupted(),不會重置當前線程的中斷狀態
測試線程當前是否已經中斷,但是不能清除狀態標識。
測試方法驗證:
1:
第一個紅框中斷的線程是我們自己創建的thread線程,我調用的interrupted(),由上面源碼可知是判斷當前線程的中斷狀態,當前線程是main線程,我根本沒有中斷過main線程,所以2次調用均返回“false”
2:
第一個紅框中斷的線程是當前線程(main線程),我調用的interrupted(),由上面源碼可知是判斷當前線程的中斷狀態,當前線程是main線程,所以第1次調用結果返回“true”,因為我確實中斷了main線程
由源碼可知interrupted()調用的是isInterrupted(),并會重置中斷狀態,所以第一次調用之后把中斷狀態給重置了,從中斷狀態重置為非中斷狀態,所以第2次調用的結果返回“false”
3:
第一個紅框中斷的線程是我們自己創建的thread線程,我調用的isInterrupted(),由上面源碼可知是判斷執行該方法的對象所表示線程的中斷狀態,也就是thread引用所表示的線程的中斷狀態,所以第1次調用結果返回“true”,
由源碼可知isInterrupted()不會重置中斷狀態,所以第一次調用之后沒有把中斷狀態給重置(從中斷狀態重置為非中斷狀態),所以第2次調用的結果還返回“true”
到此,相信大家對“java中斷線程有哪幾種方式”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。