日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

(转-这篇文章非常棒) Thread的中断机制(interrupt)

發布時間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (转-这篇文章非常棒) Thread的中断机制(interrupt) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自: Thread的中斷機制(interrupt)-這篇文章非常棒

Thread的中斷機制(interrupt) - 寂靜沙灘 - 博客園先看收集了別人的文章,全面的了解下java的中斷:中斷線程線程的thread.interrupt()方法是中斷線程,將會設置該線程的中斷狀態位,即設置為true,中斷的結果線程是死亡、還是等待新的任務https://www.cnblogs.com/onlywujun/p/3565082.html


先看收集了別人的文章,全面的了解下java的中斷:

中斷線程

線程的thread.interrupt()方法是中斷線程,將會設置該線程的中斷狀態位,即設置為true,中斷的結果線程是死亡、還是等待新的任務或是繼續運行至下一步,就取決于這個程序本身。線程會不時地檢測這個中斷標示位,以判斷線程是否應該被中斷(中斷標示值是否為true)。它并不像stop方法那樣會中斷一個正在運行的線程。

判斷線程是否被中斷

判斷某個線程是否已被發送過中斷請求,請使用Thread.currentThread().isInterrupted()方法(因為它將線程中斷標示位設置為true后,不會立刻清除中斷標示位,即不會將中斷標設置為false),而不要使用thread.interrupted()(該方法調用后會將中斷標示位清除,即重新設置為false)方法來判斷,下面是線程在循環中時的中斷方式:

while(!Thread.currentThread().isInterrupted() && more work to do){do more work }

如何中斷線程

如果一個線程處于了阻塞狀態(如線程調用了thread.sleep、thread.join、thread.wait、1.5中的condition.await、以及可中斷的通道上的 I/O 操作方法后可進入阻塞狀態),則在線程在檢查中斷標示時如果發現中斷標示為true,則會在這些阻塞方法(sleep、join、wait、1.5中的condition.await及可中斷的通道上的 I/O 操作方法)調用處拋出InterruptedException異常,并且在拋出異常后立即將線程的中斷標示位清除,即重新設置為false。拋出異常是為了線程從阻塞狀態醒過來,并在結束線程前讓程序員有足夠的時間來處理中斷請求。

注,synchronized在獲鎖的過程中是不能被中斷的,意思是說如果產生了死鎖,則不可能被中斷(請參考后面的測試例子)。與synchronized功能相似的reentrantLock.lock()方法也是一樣,它也不可中斷的,即如果發生死鎖,那么reentrantLock.lock()方法無法終止,如果調用時被阻塞,則它一直阻塞到它獲取到鎖為止。但是如果調用帶超時的tryLock方法reentrantLock.tryLock(long timeout, TimeUnit unit),那么如果線程在等待時被中斷,將拋出一個InterruptedException異常,這是一個非常有用的特性,因為它允許程序打破死鎖。你也可以調用reentrantLock.lockInterruptibly()方法,它就相當于一個超時設為無限的tryLock方法。

沒有任何語言方面的需求一個被中斷的線程應該終止。中斷一個線程只是為了引起該線程的注意,被中斷線程可以決定如何應對中斷。某些線程非常重要,以至于它們應該不理會中斷,而是在處理完拋出的異常之后繼續執行,但是更普遍的情況是,一個線程將把中斷看作一個終止請求,這種線程的run方法遵循如下形式:

public void run() {try {.../** 不管循環里是否調用過線程阻塞的方法如sleep、join、wait,這里還是需要加上* !Thread.currentThread().isInterrupted()條件,雖然拋出異常后退出了循環,顯* 得用阻塞的情況下是多余的,但如果調用了阻塞方法但沒有阻塞時,這樣會更安全、更及時。*/while (!Thread.currentThread().isInterrupted()&& more work to do) {do more work }} catch (InterruptedException e) {//線程在wait或sleep期間被中斷了} finally {//線程結束前做一些清理工作} }

上面是while循環在try塊里,如果try在while循環里時,因該在catch塊里重新設置一下中斷標示,因為拋出InterruptedException異常后,中斷標示位會自動清除,此時應該這樣:

public void run() {while (!Thread.currentThread().isInterrupted()&& more work to do) {try {...sleep(delay);} catch (InterruptedException e) {Thread.currentThread().interrupt();//重新設置中斷標示}} }

底層中斷異常處理方式

另外不要在你的底層代碼里捕獲InterruptedException異常后不處理,會處理不當,如下:

void mySubTask(){...try{sleep(delay);}catch(InterruptedException e){}//不要這樣做... }

如果你不知道拋InterruptedException異常后如何處理,那么你有如下好的建議處理方式:
1、在catch子句中,調用Thread.currentThread.interrupt()來設置中斷狀態(因為拋出異常后中斷標示會被清除),讓外界通過判斷Thread.currentThread().isInterrupted()標示來決定是否終止線程還是繼續下去,應該這樣做:

void mySubTask() {...try {sleep(delay);} catch (InterruptedException e) {Thread.currentThread().isInterrupted();}... }

2、或者,更好的做法就是,不使用try來捕獲這樣的異常,讓方法直接拋出:

void mySubTask() throws InterruptedException {...sleep(delay);... }

中斷應用

使用中斷信號量中斷非阻塞狀態的線程

中斷線程最好的,最受推薦的方式是,使用共享變量(shared variable)發出信號,告訴線程必須停止正在運行的任務。線程必須周期性的核查這一變量,然后有秩序地中止任務。Example2描述了這一方式:

class Example2 extends Thread {volatile boolean stop = false;// 線程中斷信號量public static void main(String args[]) throws Exception {Example2 thread = new Example2();System.out.println("Starting thread...");thread.start();Thread.sleep(3000);System.out.println("Asking thread to stop...");// 設置中斷信號量thread.stop = true;Thread.sleep(3000);System.out.println("Stopping application...");}public void run() {// 每隔一秒檢測一下中斷信號量while (!stop) {System.out.println("Thread is running...");long time = System.currentTimeMillis();/** 使用while循環模擬 sleep 方法,這里不要使用sleep,否則在阻塞時會 拋* InterruptedException異常而退出循環,這樣while檢測stop條件就不會執行,* 失去了意義。*/while ((System.currentTimeMillis() - time < 1000)) {}}System.out.println("Thread exiting under request...");} }

使用thread.interrupt()中斷非阻塞狀態線程

雖然Example2該方法要求一些編碼,但并不難實現。同時,它給予線程機會進行必要的清理工作。這里需注意一點的是需將共享變量定義成volatile 類型或將對它的一切訪問封入同步的塊/方法(synchronized blocks/methods)中。上面是中斷一個非阻塞狀態的線程的常見做法,但對非檢測isInterrupted()條件會更簡潔:

class Example2 extends Thread {public static void main(String args[]) throws Exception {Example2 thread = new Example2();System.out.println("Starting thread...");thread.start();Thread.sleep(3000);System.out.println("Asking thread to stop...");// 發出中斷請求thread.interrupt();Thread.sleep(3000);System.out.println("Stopping application...");}public void run() {// 每隔一秒檢測是否設置了中斷標示while (!Thread.currentThread().isInterrupted()) {System.out.println("Thread is running...");long time = System.currentTimeMillis();// 使用while循環模擬 sleepwhile ((System.currentTimeMillis() - time < 1000) ) {}}System.out.println("Thread exiting under request...");} }

到目前為止一切順利!但是,當線程等待某些事件發生而被阻塞,又會發生什么?當然,如果線程被阻塞,它便不能核查共享變量,也就不能停止。這在許多情況下會發生,例如調用Object.wait()、ServerSocket.accept()和DatagramSocket.receive()時,這里僅舉出一些。

他們都可能永久的阻塞線程。即使發生超時,在超時期滿之前持續等待也是不可行和不適當的,所以,要使用某種機制使得線程更早地退出被阻塞的狀態。下面就來看一下中斷阻塞線程技術。

使用thread.interrupt()中斷阻塞狀態線程

Thread.interrupt()方法不會中斷一個正在運行的線程。這一方法實際上完成的是,設置線程的中斷標示位,在線程受到阻塞的地方(如調用sleep、wait、join等地方)拋出一個異常InterruptedException,并且中斷狀態也將被清除,這樣線程就得以退出阻塞的狀態。下面是具體實現:

class Example3 extends Thread {public static void main(String args[]) throws Exception {Example3 thread = new Example3();System.out.println("Starting thread...");thread.start();Thread.sleep(3000);System.out.println("Asking thread to stop...");thread.interrupt();// 等中斷信號量設置后再調用Thread.sleep(3000);System.out.println("Stopping application...");}public void run() {while (!Thread.currentThread().isInterrupted()) {System.out.println("Thread running...");try {/** 如果線程阻塞,將不會去檢查中斷信號量stop變量,所 以thread.interrupt()* 會使阻塞線程從阻塞的地方拋出異常,讓阻塞線程從阻塞狀態逃離出來,并* 進行異常塊進行 相應的處理*/Thread.sleep(1000);// 線程阻塞,如果線程收到中斷操作信號將拋出異常} catch (InterruptedException e) {System.out.println("Thread interrupted...");/** 如果線程在調用 Object.wait()方法,或者該類的 join() 、sleep()方法* 過程中受阻,則其中斷狀態將被清除*/System.out.println(this.isInterrupted());// false//中不中斷由自己決定,如果需要真真中斷線程,則需要重新設置中斷位,如果//不需要,則不用調用Thread.currentThread().interrupt();}}System.out.println("Thread exiting under request...");} }

一旦Example3中的Thread.interrupt()被調用,線程便收到一個異常,于是逃離了阻塞狀態并確定應該停止。上面我們還可以使用共享信號量來替換!Thread.currentThread().isInterrupted()條件,但不如它簡潔。

死鎖狀態線程無法被中斷

Example4試著去中斷處于死鎖狀態的兩個線程,但這兩個線都沒有收到任何中斷信號(拋出異常),所以interrupt()方法是不能中斷死鎖線程的,因為鎖定的位置根本無法拋出異常:

class Example4 extends Thread {public static void main(String args[]) throws Exception {final Object lock1 = new Object();final Object lock2 = new Object();Thread thread1 = new Thread() {public void run() {deathLock(lock1, lock2);}};Thread thread2 = new Thread() {public void run() {// 注意,這里在交換了一下位置deathLock(lock2, lock1);}};System.out.println("Starting thread...");thread1.start();thread2.start();Thread.sleep(3000);System.out.println("Interrupting thread...");thread1.interrupt();thread2.interrupt();Thread.sleep(3000);System.out.println("Stopping application...");}static void deathLock(Object lock1, Object lock2) {try {synchronized (lock1) {Thread.sleep(10);// 不會在這里死掉synchronized (lock2) {// 會鎖在這里,雖然阻塞了,但不會拋異常System.out.println(Thread.currentThread());}}} catch (InterruptedException e) {e.printStackTrace();System.exit(1);}} }

中斷I/O操作

然而,如果線程在I/O操作進行時被阻塞,又會如何?I/O操作可以阻塞線程一段相當長的時間,特別是牽扯到網絡應用時。例如,服務器可能需要等待一個請求(request),又或者,一個網絡應用程序可能要等待遠端主機的響應。

實現此InterruptibleChannel接口的通道是可中斷的:如果某個線程在可中斷通道上因調用某個阻塞的 I/O 操作(常見的操作一般有這些:serverSocketChannel. accept()、socketChannel.connect、socketChannel.open、socketChannel.read、socketChannel.write、fileChannel.read、fileChannel.write)而進入阻塞狀態,而另一個線程又調用了該阻塞線程的 interrupt 方法,這將導致該通道被關閉,并且已阻塞線程接將會收到ClosedByInterruptException,并且設置已阻塞線程的中斷狀態。另外,如果已設置某個線程的中斷狀態并且它在通道上調用某個阻塞的 I/O 操作,則該通道將關閉并且該線程立即接收到 ClosedByInterruptException;并仍然設置其中斷狀態。如果情況是這樣,其代碼的邏輯和第三個例子中的是一樣的,只是異常不同而已。

如果你正使用通道(channels)(這是在Java 1.4中引入的新的I/O API),那么被阻塞的線程將收到一個ClosedByInterruptException異常。但是,你可能正使用Java1.0之前就存在的傳統的I/O,而且要求更多的工作。既然這樣,Thread.interrupt()將不起作用,因為線程將不會退出被阻塞狀態。Example5描述了這一行為。盡管interrupt()被調用,線程也不會退出被阻塞狀態,比如ServerSocket的accept方法根本不拋出異常。

很幸運,Java平臺為這種情形提供了一項解決方案,即調用阻塞該線程的套接字的close()方法。在這種情形下,如果線程被I/O操作阻塞,當調用該套接字的close方法時,該線程在調用accept地方法將接收到一個SocketException(SocketException為IOException的子異常)異常,這與使用interrupt()方法引起一個InterruptedException異常被拋出非常相似,(注,如果是流因讀寫阻塞后,調用流的close方法也會被阻塞,根本不能調用,更不會拋IOExcepiton,此種情況下怎樣中斷?我想可以轉換為通道來操作流可以解決,比如文件通道)。下面是具體實現:

class Example6 extends Thread {volatile ServerSocket socket;public static void main(String args[]) throws Exception {Example6 thread = new Example6();System.out.println("Starting thread...");thread.start();Thread.sleep(3000);System.out.println("Asking thread to stop...");Thread.currentThread().interrupt();// 再調用interrupt方法thread.socket.close();// 再調用close方法try {Thread.sleep(3000);} catch (InterruptedException e) {}System.out.println("Stopping application...");}public void run() {try {socket = new ServerSocket(8888);} catch (IOException e) {System.out.println("Could not create the socket...");return;}while (!Thread.currentThread().isInterrupted()) {System.out.println("Waiting for connection...");try {socket.accept();} catch (IOException e) {System.out.println("accept() failed or interrupted...");Thread.currentThread().interrupt();//重新設置中斷標示位}}System.out.println("Thread exiting under request...");} }

---------------------------------------------------------------------------------------------------------------------------------------------------------

一、沒有任何語言方面的需求一個被中斷的線程應該終止。中斷一個線程只是為了引起該線程的注意,被中斷線程可以決定如何應對中斷。

二、對于處于sleep,join等操作的線程,如果被調用interrupt()后,會拋出InterruptedException,然后線程的中斷標志位會由true重置為false,因為線程為了處理異常已經重新處于就緒狀態。

三、不可中斷的操作,包括進入synchronized段以及Lock.lock(),inputSteam.read()等,調用interrupt()對于這幾個問題無效,因為它們都不拋出中斷異常。如果拿不到資源,它們會無限期阻塞下去。

對于Lock.lock(),可以改用Lock.lockInterruptibly(),可被中斷的加鎖操作,它可以拋出中斷異常。等同于等待時間無限長的Lock.tryLock(long time,?TimeUnit unit)。

對于inputStream等資源,有些(實現了interruptibleChannel接口)可以通過close()方法將資源關閉,對應的阻塞也會被放開。

 

首先,看看Thread類里的幾個方法:

public static boolean?interrupted測試當前線程是否已經中斷。線程的中斷狀態?由該方法清除。換句話說,如果連續兩次調用該方法,則第二次調用將返回 false。

public boolean?isInterrupted()

測試線程是否已經中斷。線程的中斷狀態?不受該方法的影響。

public void?interrupt()

中斷線程。

上面列出了與中斷有關的幾個方法及其行為,可以看到interrupt是中斷線程。如果不了解Java的中斷機制,這樣的一種解釋極容易造成誤解,認為調用了線程的interrupt方法就一定會中斷線程。

其實,Java的中斷是一種協作機制。也就是說調用線程對象的interrupt方法并不一定就中斷了正在運行的線程,它只是要求線程自己在合適的時機中斷自己。每個線程都有一個boolean的中斷狀態(這個狀態不在Thread的屬性上),interrupt方法僅僅只是將該狀態置為true。

比如對正常運行的線程調用interrupt()并不能終止他,只是改變了interrupt標示符。

一般說來,如果一個方法聲明拋出InterruptedException,表示該方法是可中斷的,比如wait,sleep,join,也就是說可中斷方法會對interrupt調用做出響應(例如sleep響應interrupt的操作包括清除中斷狀態,拋出InterruptedException),異常都是由可中斷方法自己拋出來的,并不是直接由interrupt方法直接引起的。

Object.wait, Thread.sleep方法,會不斷的輪詢監聽 interrupted 標志位,發現其設置為true后,會停止阻塞并拋出 InterruptedException異常。

--------------------------------------------------------------------------------------------------------------------------------------------------------------

看了以上的說明,對java中斷的使用肯定是會了,但我想知道的是阻塞了的線程是如何通過interuppt方法完成停止阻塞并拋出interruptedException的,這就要看Thread中native的interuppt0方法了。

第一步學習Java的JNI調用Native方法。

第二步下載openjdk的源代碼,找到目錄結構里的openjdk-src\jdk\src\share\native\java\lang\Thread.c文件。

#include "jni.h" #include "jvm.h"#include "java_lang_Thread.h"#define THD "Ljava/lang/Thread;" #define OBJ "Ljava/lang/Object;" #define STE "Ljava/lang/StackTraceElement;"#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))static JNINativeMethod methods[] = {{"start0", "()V", (void *)&JVM_StartThread},{"stop0", "(" OBJ ")V", (void *)&JVM_StopThread},{"isAlive", "()Z", (void *)&JVM_IsThreadAlive},{"suspend0", "()V", (void *)&JVM_SuspendThread},{"resume0", "()V", (void *)&JVM_ResumeThread},{"setPriority0", "(I)V", (void *)&JVM_SetThreadPriority},{"yield", "()V", (void *)&JVM_Yield},{"sleep", "(J)V", (void *)&JVM_Sleep},{"currentThread", "()" THD, (void *)&JVM_CurrentThread},{"countStackFrames", "()I", (void *)&JVM_CountStackFrames}, {"interrupt0", "()V", (void *)&JVM_Interrupt},{"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted},{"holdsLock", "(" OBJ ")Z", (void *)&JVM_HoldsLock},{"getThreads", "()[" THD, (void *)&JVM_GetAllThreads},{"dumpThreads", "([" THD ")[[" STE, (void *)&JVM_DumpThreads}, };#undef THD #undef OBJ #undef STEJNIEXPORT void JNICALL Java_java_lang_Thread_registerNatives(JNIEnv *env, jclass cls) {(*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods)); }

暫時還看不太懂,先去學習一下C的一些基礎。

未完待續...

總結

以上是生活随笔為你收集整理的(转-这篇文章非常棒) Thread的中断机制(interrupt)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。