您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關java如何實現(xiàn)多線程中斷,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
一、java中終止線程主要有三種方法:
①線程正常退出,即run()方法執(zhí)行完畢了
②使用Thread類中的stop()(已過期不推薦使用)方法強行終止線程。
③使用中斷機制
t.stop()調用時,終止線程,會導致該線程所持有的鎖被強制釋放,從而被其他線程所持有,因此有可能導致與預期結果不一致。下面使用中斷信號量中斷非阻塞狀態(tài)的線程中:
public class TestStopThread { public static void main(String[] args) throws InterruptedException { StopThread st = new StopThread(); st.setName("線程st"); st.start(); Thread.sleep(3000); st.stopFlag(); Thread.sleep(1000); System.out.println(st.getState()); } } class StopThread extends Thread { // 此變量必須加上volatile private volatile boolean stop = false; @Override public void run() { // 判斷線程體是否運行 while (!stop) { System.out.println("線程StopThread正在運行"); long time = System.currentTimeMillis(); /* * 使用while循環(huán)模擬 sleep 方法,這里不要使用sleep,否則在阻塞時會拋 * InterruptedException異常而退出循環(huán),這樣while檢測stop條件就不會執(zhí)行, * 失去了意義。 */ while ((System.currentTimeMillis() - time < 1000)) {} } System.out.println("線程StopThread正在結束"); } // 線程終止 public void stopFlag() { stop = true; } }
二、java線程中斷機制
下面看看Thread類里的三個方法:
1. public static boolean interrupted():檢測當前線程是否已經中斷。線程的中斷狀態(tài)由該方法清除。如果連續(xù)兩次調用該方法,則第二次調用將返回 false(在第一次調用已清除了其中斷狀態(tài)之后,且第二次調用檢驗完中斷狀態(tài)前,當前線程再次中斷的情況除外)。
2. public boolean isInterrupted():測試線程是否已經中斷。線程的中斷狀態(tài)不受該方法的影響。
3. public void interrupt(): 中斷線程。
interrupt()只是改變中斷狀態(tài)而已. interrupt()不會終止一個正在運行的線程。
public class TestInterrupt1 { public static void main(String[] args) throws InterruptedException { Thread t = new MyThread(); t.start(); t.interrupt(); System.out.println("調用線程的interrupt()方法"); System.out.println("線程的中斷狀態(tài):" +t.isInterrupted()); } static class MyThread extends Thread { public void run() { long time = System.currentTimeMillis(); System.out.println("線程正在運行"); /* * 使用while循環(huán)模擬 sleep 方法,這里不要使用sleep,否則在阻塞時會拋 * InterruptedException異常而退出循環(huán)。 */ while ((System.currentTimeMillis() - time < 1000)) {} System.out.println("線程的中斷狀態(tài):" + Thread.interrupted()); System.out.println("線程的中斷狀態(tài)被清除:" +isInterrupted()); while ((System.currentTimeMillis() - time < 5000)) {} System.out.println("線程運行完成"); } } }
正常輸出:
調用線程的interrupt()方法 線程正在運行 線程的中斷狀態(tài):true 線程的中斷狀態(tài):true 線程的中斷狀態(tài)被清除:false 線程運行完成
實際上當調用interrupt()方法的時候,只是設置了要中斷線程的中斷狀態(tài),而此時被中斷的線程的可以通過isInterrupted()或者是Thread.interrupted()方法判斷當前線程的中斷狀態(tài)是否標志為中斷。
調用線程的wait(), wait(long)或wait(long, int)會讓它進入等待(阻塞)狀態(tài),或者調用線程的join(), join(long), join(long, int), sleep(long), sleep(long, int)也會讓它進入阻塞狀態(tài)。若線程在阻塞狀態(tài)時,調用了它的interrupt()方法,那么它的“中斷狀態(tài)”會被清除并且會收到一個InterruptedException異常。例如,線程通過wait()進入阻塞狀態(tài),此時通過interrupt()中斷該線程;調用interrupt()會立即將線程的中斷標記設為“true”,但是由于線程處于阻塞狀態(tài),所以該“中斷標記”會立即被清除為“false”,同時,會產生一個InterruptedException的異常。
public class InterruptTest extends Thread{ public static void main(String[] args) throws InterruptedException { InterruptTest t=new InterruptTest(); t.start(); Thread.sleep(1000); t.interrupt(); } public void run(){ while(!Thread.interrupted()){ System.out.println("Thread is running....."); try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
正常運行結果:
系統(tǒng)復位。我們可以手動的使用Thread.interrupted()來使當前線程的中斷狀態(tài)系統(tǒng)復位(即清除中斷狀態(tài)),其實是在sleep,wait,join這些方法內部會不斷檢查中斷狀態(tài)的值,而自己拋出的InterruptedException。
中斷:如果線程在調用Object類的wait()、wait(long)或wait(long, int)方法,或者該類的 join() 、join(long) 、join(long, int) 、sleep(long) 或 sleep(long, int) 方法過程中受阻,則其中斷狀態(tài)將被清除,它還將收到一個 InterruptedException。
如果該線程在可中斷的通道(java.nio.channels.InterruptibleChannel)上的 I/O 操作中受阻,則該通道將被關閉,該線程的中斷狀態(tài)將被設置并且該線程將收到一個 ClosedByInterruptException。
如果該線程在一個 Selector (java.nio.channels.Selector) 中受阻,則該線程的中斷狀態(tài)將被設置,它將立即從選擇操作返回,并可能帶有一個非零值,就好像調用了選擇器的 wakeup 方法一樣。
如果以前的條件都沒有保存,則該線程的中斷狀態(tài)將被設置。
中斷一個不處于活動狀態(tài)的線程不需要任何作用。
檢測中斷:如何檢測中斷決定于線程所做的事情。
如果線程調用可以拋出InterruptException的方法,則捕獲InterruptException,然后在catch塊中處理(通常是退出run方法以中斷線程)
如果調用其它方法,則可以在空閑時檢查Thread.interrupted以判斷是否收到中斷信號,確認收到中斷信號后進行處理??梢話伋鲆粋€InterruptException從而和前一種處理方法保持一致
中斷狀態(tài):線程的中斷機制是使用中斷狀態(tài)這一內部標志實現(xiàn)的。中斷狀態(tài)在調用線程的interrupt()方法時被設置(參考上面的interrupt方法說明)。
可以發(fā)現(xiàn),isInterrupted被聲明為native方法,取決于JVM底層的實現(xiàn)。調用線程的interrupt方法,并不能立即引發(fā)中斷,只是設置了JVM內部的中斷標記。因此,通過檢查中斷標記,應用程序可以做一些特殊操作,也可以完全忽略中斷。
實際上Thread.interrupt()方法實際上通過某種方式通知線程,并不會直接中止該線程。具體做什么事情由寫代碼的人決定,通常我們會中止該線程。
三、一些不會拋出 InterruptedException 的線程阻塞操作
對于某些線程阻塞操作,JVM并不會自動拋出InterruptedException異常。例如,某些I/O操作和內部鎖操作。對于這類操作,可以用其他方式模擬中斷:
1)java.io中的異步socket I/O
讀寫socket的時候,InputStream和OutputStream的read和write方法會阻塞等待,但不會響應java中斷。不過,調用Socket的close方法后,被阻塞線程會拋出SocketException異常。
2)利用Selector實現(xiàn)的異步I/O
如果線程被阻塞于Selector.select(在java.nio.channels中),調用wakeup方法會引起ClosedSelectorException異常。
3)鎖獲取
如果線程在等待獲取一個內部鎖,我們將無法中斷它。但是,利用Lock類的lockInterruptibly方法,我們可以在等待鎖的同時,提供中斷能力。
關于“java如何實現(xiàn)多線程中斷”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。