Java中的interrupted()和isInterrupted()
1、前言
當提及如何終止一個線程時,部分讀者通常立馬想到的方法肯定是stop(),但是stop()方法并不被推薦使用(很多規(guī)范中是禁止使用的),其原因是強制終止一個線程,會導致程序不正常的結束,會出現(xiàn)資源未正確釋放、程序結果不正確等等問題。而是否終止一個線程應該把這個控制權轉交給當前被終止的線程本身,此時采用的辦法就是 ****interrupt()方法來終止,該方法相當于修改一個共享變量的值,當運行中的線程判斷當前值為false則繼續(xù)運行,如果有地方調用當前thread的interrupt()方法,那么這個值將變?yōu)?code>true,此時當前線程可以根據(jù)這個值的修改來正確的終止線程的運行。
2、API
在java.lang.Thread中主要提供了如下與線程中斷相關的方法,其具體方法名與主要作用如下表所示。
| 方法名 | 方法作用 |
|---|---|
| public void?interrupt() | 中斷此線程 |
| public static boolean?interrupted() | 測試當前線程是否被中斷,該方法會恢復(清除)中斷標志 |
| public boolean?isInterrupted() | 測試當前線程是否被中斷,該方法只會獲取中斷標志,不會恢復(清除)中斷標志 |
| private native boolean?isInterrupted(boolean?ClearInterrupted); | interrupted()和isInterrupted()最終調用,該方法是native本地方法,在jvm中具體實現(xiàn),也是獲取線程中斷標志真正調用的方法,參數(shù)ClearInterrupted意思是是否恢復(清除)中斷標志 |
源碼:
/**
* 中斷此線程
*/
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
/**
* 測試當前線程是否被中斷,返回中斷標志
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
/**
* 測試當前線程是否被中斷,返回中斷標志
*/
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* 線程是否被中斷native方法,ClearInterrupted為是否清除中斷標志參數(shù)
*/
private native boolean isInterrupted(boolean ClearInterrupted);
/**
* 中斷當前線程的native方法
*/
private native void interrupt0();
3、interrupted()和isInterrupted()區(qū)別
看了上述API講述和Thread中的源碼,已經(jīng)清楚interrupted()和isInterrupted()的主要區(qū)別了
interrupted()為靜態(tài)方法,isInterrupted()為普通方法
interrupted() 返回中斷標志且清除(恢復)中斷標志,isInterrupted()僅返回中斷標志
3.1 使用方法
我們先驗證中斷異常響應,通過如下兩種方法的使用示例來介紹,注意Runner中的run方法的部分區(qū)別
方法一
package com.liziba.p7;
import java.util.concurrent.TimeUnit;
/**
* <p>
*
* </p>
*
* @Author: Liziba
* @Date: 2021/6/24 21:05
*/
public class ThreadInterruptedDemo {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new Runner(), "Thread-01");
t1.start();
// 主線程睡眠1秒,保證t1的充分執(zhí)行
TimeUnit.SECONDS.sleep(1);
// 發(fā)起中斷
t1.interrupt();
}
static class Runner implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName() + " is running .");
}
}
}
}
輸出結果:

可以看到線程在執(zhí)行數(shù)次后終止運行
方法二
package com.liziba.p7;
import java.util.concurrent.TimeUnit;
/**
* <p>
*
* </p>
*
* @Author: Liziba
* @Date: 2021/6/24 21:18
*/
public class ThreadInterruptedDemo {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new Runner(), "Thread-01");
t1.start();
// 主線程睡眠2秒,保證t1的充分執(zhí)行
TimeUnit.SECONDS.sleep(1);
// 發(fā)起中斷
t1.interrupt();
}
static class Runner implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName() + " is running .");
try {
// 睡眠2秒,保證主線程發(fā)起的中斷能被捕獲
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
// 不對中斷做任何處理,try住異常,打印
e.printStackTrace();
}
}
}
}
}
輸出結果:

可以看到main線程中發(fā)起的t1線程中斷,被捕獲住異常后,未做任何處理,線程繼續(xù)持續(xù)不斷的運行
總結上述兩種方式:
方法一和方法二,均通過判斷Thread.currentThread().isInterrupted()的值來運行run方法中的邏輯,Thread.currentThread().isInterrupted()在線程未中斷時返回false,當main線程中執(zhí)行 t1.interrupt()時,線程t1被中斷,Thread.currentThread().isInterrupted()的值變?yōu)?code>false;在方法一中,獲取到這個變化后直接結束運行;在方法二中,由于sleep()使得線程阻塞會響應中斷,但是此時我僅僅catch住異常,并沒有對中斷做任何處理,這里有個知識點是,線程響應中斷拋出異常時,會恢復(清除)中斷標志,所以t1.interrupt()對中斷標志的修改又被恢復了,程序仍然不斷的運行。
接下來我們來驗證interrupted()對于中斷的標志的清除
package com.liziba.p7;
import java.util.concurrent.TimeUnit;
/**
* <p>
* isInterrupted()
* </p>
*
* @Author: Liziba
* @Date: 2021/6/24 21:20
*/
public class ThreadInterruptDemo2 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runner(), "Thread-1");
thread.start();
TimeUnit.SECONDS.sleep(2);
thread.interrupt();
}
static class Runner implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +" interrupted flag is " + Thread.currentThread().isInterrupted());
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println(Thread.currentThread().getName() + " is running .");
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// 響應中斷,拋出異常后中斷位置會被復位,自己中斷自己
Thread.currentThread().interrupt();
// 這里調用isInterrupted()獲取當前的中斷標志
System.out.println(Thread.currentThread().getName()
+" interrupted flag is " + Thread.currentThread().isInterrupted());
}
}
}
}
}
輸出結果:
這里證明interrupted()不清楚中斷標志,線程在獲取到 thread.interrupt()發(fā)起中斷后,執(zhí)行結束。

將上述catch中的Thread.currentThread().isInterrupted()修改為Thread.interrupted()再次運行
package com.liziba.p7;
import java.util.concurrent.TimeUnit;
/**
* <p>
*
* </p>
*
* @Author: Liziba
* @Date: 2021/6/24 21:23
*/
public class ThreadInterruptDemo2 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runner(), "Thread-1");
thread.start();
TimeUnit.SECONDS.sleep(2);
thread.interrupt();
}
// 區(qū)別在catch中
static class Runner implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +" interrupted flag is " + Thread.currentThread().isInterrupted());
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println(Thread.currentThread().getName() + " is running .");
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// 響應中斷,拋出異常后中斷位置會被復位,自己中斷自己
Thread.currentThread().interrupt();
// 注意區(qū)別在這里
System.out.println(Thread.currentThread().getName()
+" interrupted flag is " + Thread.interrupted());
}
}
}
}
}
輸出結果:
線程也響應到了 thread.interrupt()的中斷,但是由于catch中調用了Thread.interrupted(),對中斷標志進行了清除,所以!Thread.currentThread().isInterrupted()判斷仍然等于true,線程繼續(xù)不斷的運行

看到這里,應該已經(jīng)理解了這兩個方法的主要區(qū)別和其使用,最后我們來看下一個源碼中的使用案例。我們通過觀看AbstractQueuedSynchronizer(AQS)中的await()方法,來看其在源碼中的使用。
public final void await() throws InterruptedException {
// 判斷當前線程是否被中斷,如果被中斷則恢復中斷標志
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
AbstractQueuedSynchronizer(AQS)源碼中使用靜態(tài)Thread.interrupted(),判斷當前線程是否被中斷,并恢復中斷標志,如果線程已被中斷則拋出InterruptedException中斷異常。清除標志位的作用就是為了當前線程響應過中斷后,再次進入的時候可以進行后續(xù)操作。
到此這篇關于Java中的interrupted()和isInterrupted()的文章就介紹到這了,更多相關interrupted()和isInterrupted()內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Spring MVC+FastJson+Swagger集成的完整實例教程
這篇文章主要給大家分享介紹了關于Spring MVC+FastJson+Swagger集成的完整實例教程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2018-04-04
springboot與數(shù)據(jù)庫返回數(shù)據(jù)中文亂碼
大家好,本篇文章主要講的是springboot與數(shù)據(jù)庫返回數(shù)據(jù)中文亂碼,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2022-01-01
JDK源碼之線程并發(fā)協(xié)調神器CountDownLatch和CyclicBarrier詳解
我一直認為程序是對于現(xiàn)實世界的邏輯描述,而在現(xiàn)實世界中很多事情都需要各方協(xié)調合作才能完成,就好比完成一個平臺的交付不可能只靠一個人,而需要研發(fā)、測試、產(chǎn)品以及項目經(jīng)理等不同角色人員進行通力合作才能完成最終的交付2022-02-02
spring整合redis實現(xiàn)數(shù)據(jù)緩存的實例代碼
這篇文章主要介紹了spring整合redis實現(xiàn)數(shù)據(jù)緩存,需要的朋友可以參考下2018-09-09
BeanUtils.copyProperties復制對象結果為空的原因分析
這篇文章主要介紹了BeanUtils.copyProperties復制對象結果為空的原因分析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06
Spring Boot 2和Redis例子實現(xiàn)過程解析
這篇文章主要介紹了Spring Boot2發(fā)布與調用REST服務過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-11-11

