Java中的interrupted()和isInterrupted()
1、前言
當(dāng)提及如何終止一個線程時,部分讀者通常立馬想到的方法肯定是stop(),但是stop()方法并不被推薦使用(很多規(guī)范中是禁止使用的),其原因是強(qiáng)制終止一個線程,會導(dǎo)致程序不正常的結(jié)束,會出現(xiàn)資源未正確釋放、程序結(jié)果不正確等等問題。而是否終止一個線程應(yīng)該把這個控制權(quán)轉(zhuǎn)交給當(dāng)前被終止的線程本身,此時采用的辦法就是 ****interrupt()方法來終止,該方法相當(dāng)于修改一個共享變量的值,當(dāng)運(yùn)行中的線程判斷當(dāng)前值為false則繼續(xù)運(yùn)行,如果有地方調(diào)用當(dāng)前thread的interrupt()方法,那么這個值將變?yōu)?code>true,此時當(dāng)前線程可以根據(jù)這個值的修改來正確的終止線程的運(yùn)行。
2、API
在java.lang.Thread中主要提供了如下與線程中斷相關(guān)的方法,其具體方法名與主要作用如下表所示。
| 方法名 | 方法作用 |
|---|---|
| public void?interrupt() | 中斷此線程 |
| public static boolean?interrupted() | 測試當(dāng)前線程是否被中斷,該方法會恢復(fù)(清除)中斷標(biāo)志 |
| public boolean?isInterrupted() | 測試當(dāng)前線程是否被中斷,該方法只會獲取中斷標(biāo)志,不會恢復(fù)(清除)中斷標(biāo)志 |
| private native boolean?isInterrupted(boolean?ClearInterrupted); | interrupted()和isInterrupted()最終調(diào)用,該方法是native本地方法,在jvm中具體實(shí)現(xiàn),也是獲取線程中斷標(biāo)志真正調(diào)用的方法,參數(shù)ClearInterrupted意思是是否恢復(fù)(清除)中斷標(biāo)志 |
源碼:
/**
* 中斷此線程
*/
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();
}
/**
* 測試當(dāng)前線程是否被中斷,返回中斷標(biāo)志
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
/**
* 測試當(dāng)前線程是否被中斷,返回中斷標(biāo)志
*/
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* 線程是否被中斷native方法,ClearInterrupted為是否清除中斷標(biāo)志參數(shù)
*/
private native boolean isInterrupted(boolean ClearInterrupted);
/**
* 中斷當(dāng)前線程的native方法
*/
private native void interrupt0();
3、interrupted()和isInterrupted()區(qū)別
看了上述API講述和Thread中的源碼,已經(jīng)清楚interrupted()和isInterrupted()的主要區(qū)別了
interrupted()為靜態(tài)方法,isInterrupted()為普通方法
interrupted() 返回中斷標(biāo)志且清除(恢復(fù))中斷標(biāo)志,isInterrupted()僅返回中斷標(biāo)志
3.1 使用方法
我們先驗(yàn)證中斷異常響應(yīng),通過如下兩種方法的使用示例來介紹,注意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 .");
}
}
}
}
輸出結(jié)果:

可以看到線程在執(zhí)行數(shù)次后終止運(yùn)行
方法二
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();
}
}
}
}
}
輸出結(jié)果:

可以看到main線程中發(fā)起的t1線程中斷,被捕獲住異常后,未做任何處理,線程繼續(xù)持續(xù)不斷的運(yùn)行
總結(jié)上述兩種方式:
方法一和方法二,均通過判斷Thread.currentThread().isInterrupted()的值來運(yùn)行run方法中的邏輯,Thread.currentThread().isInterrupted()在線程未中斷時返回false,當(dāng)main線程中執(zhí)行 t1.interrupt()時,線程t1被中斷,Thread.currentThread().isInterrupted()的值變?yōu)?code>false;在方法一中,獲取到這個變化后直接結(jié)束運(yùn)行;在方法二中,由于sleep()使得線程阻塞會響應(yīng)中斷,但是此時我僅僅catch住異常,并沒有對中斷做任何處理,這里有個知識點(diǎn)是,線程響應(yīng)中斷拋出異常時,會恢復(fù)(清除)中斷標(biāo)志,所以t1.interrupt()對中斷標(biāo)志的修改又被恢復(fù)了,程序仍然不斷的運(yùn)行。
接下來我們來驗(yàn)證interrupted()對于中斷的標(biāo)志的清除
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) {
// 響應(yīng)中斷,拋出異常后中斷位置會被復(fù)位,自己中斷自己
Thread.currentThread().interrupt();
// 這里調(diào)用isInterrupted()獲取當(dāng)前的中斷標(biāo)志
System.out.println(Thread.currentThread().getName()
+" interrupted flag is " + Thread.currentThread().isInterrupted());
}
}
}
}
}
輸出結(jié)果:
這里證明interrupted()不清楚中斷標(biāo)志,線程在獲取到 thread.interrupt()發(fā)起中斷后,執(zhí)行結(jié)束。

將上述catch中的Thread.currentThread().isInterrupted()修改為Thread.interrupted()再次運(yùn)行
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) {
// 響應(yīng)中斷,拋出異常后中斷位置會被復(fù)位,自己中斷自己
Thread.currentThread().interrupt();
// 注意區(qū)別在這里
System.out.println(Thread.currentThread().getName()
+" interrupted flag is " + Thread.interrupted());
}
}
}
}
}
輸出結(jié)果:
線程也響應(yīng)到了 thread.interrupt()的中斷,但是由于catch中調(diào)用了Thread.interrupted(),對中斷標(biāo)志進(jìn)行了清除,所以!Thread.currentThread().isInterrupted()判斷仍然等于true,線程繼續(xù)不斷的運(yùn)行

看到這里,應(yīng)該已經(jīng)理解了這兩個方法的主要區(qū)別和其使用,最后我們來看下一個源碼中的使用案例。我們通過觀看AbstractQueuedSynchronizer(AQS)中的await()方法,來看其在源碼中的使用。
public final void await() throws InterruptedException {
// 判斷當(dāng)前線程是否被中斷,如果被中斷則恢復(fù)中斷標(biāo)志
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(),判斷當(dāng)前線程是否被中斷,并恢復(fù)中斷標(biāo)志,如果線程已被中斷則拋出InterruptedException中斷異常。清除標(biāo)志位的作用就是為了當(dāng)前線程響應(yīng)過中斷后,再次進(jìn)入的時候可以進(jìn)行后續(xù)操作。
到此這篇關(guān)于Java中的interrupted()和isInterrupted()的文章就介紹到這了,更多相關(guān)interrupted()和isInterrupted()內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java詳解實(shí)現(xiàn)ATM機(jī)模擬系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了如何利用Java語言實(shí)現(xiàn)控制臺版本的ATM銀行管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-06-06
Spring MVC+FastJson+Swagger集成的完整實(shí)例教程
這篇文章主要給大家分享介紹了關(guān)于Spring MVC+FastJson+Swagger集成的完整實(shí)例教程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-04-04
java中pdf轉(zhuǎn)圖片的實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄猨ava中pdf轉(zhuǎn)圖片的實(shí)現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-12-12
springboot與數(shù)據(jù)庫返回數(shù)據(jù)中文亂碼
大家好,本篇文章主要講的是springboot與數(shù)據(jù)庫返回數(shù)據(jù)中文亂碼,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2022-01-01
JDK源碼之線程并發(fā)協(xié)調(diào)神器CountDownLatch和CyclicBarrier詳解
我一直認(rèn)為程序是對于現(xiàn)實(shí)世界的邏輯描述,而在現(xiàn)實(shí)世界中很多事情都需要各方協(xié)調(diào)合作才能完成,就好比完成一個平臺的交付不可能只靠一個人,而需要研發(fā)、測試、產(chǎn)品以及項(xiàng)目經(jīng)理等不同角色人員進(jìn)行通力合作才能完成最終的交付2022-02-02
spring整合redis實(shí)現(xiàn)數(shù)據(jù)緩存的實(shí)例代碼
這篇文章主要介紹了spring整合redis實(shí)現(xiàn)數(shù)據(jù)緩存,需要的朋友可以參考下2018-09-09
BeanUtils.copyProperties復(fù)制對象結(jié)果為空的原因分析
這篇文章主要介紹了BeanUtils.copyProperties復(fù)制對象結(jié)果為空的原因分析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06
Spring Boot 2和Redis例子實(shí)現(xiàn)過程解析
這篇文章主要介紹了Spring Boot2發(fā)布與調(diào)用REST服務(wù)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-11-11

