Java線程中斷機(jī)制interrupt、isInterrupted、interrupted方法詳解
什么是中斷
- 一個(gè)線程不應(yīng)該由其他線程來(lái)強(qiáng)制中斷或停止,而是應(yīng)該由線程自己自行停止,所以,Thread.stop、Thread.suspend、Thread. resume都已經(jīng)被廢棄了
- 在Java中沒(méi)有辦法立即停止一條線程,然而停止線程卻顯得尤為重要,如取消一個(gè)耗時(shí)操作。因此,Java提供了一種用于停止線程的機(jī)制 — 中斷
- 中斷只是一種協(xié)作機(jī)制,Java沒(méi)有給中斷增加任何語(yǔ)法,中斷的過(guò)程完全需要程序員自己實(shí)現(xiàn)
- 若要中斷一個(gè)線程,你需要手動(dòng)調(diào)用該線程的interrupt方法,該方法也僅僅是將線程對(duì)象的中斷標(biāo)識(shí)設(shè)為true
- 每個(gè)線程對(duì)象中都有一個(gè)標(biāo)識(shí),用于標(biāo)識(shí)線程是否被中斷;該標(biāo)識(shí)位為true表示中斷,為false表示未中斷,通過(guò)調(diào)用線程對(duì)象的interrupt方法將線程的標(biāo)識(shí)位設(shè)為true,可以在別的線程中調(diào)用,也可以在自己的線程中調(diào)用
源碼解讀(中斷的相關(guān)API)
void interrupt( )實(shí)例方法
interrupt( )僅僅是設(shè)置線程的中斷狀態(tài)為true,不會(huì)停止線程
源碼解讀(如果這個(gè)線程因?yàn)閣ait()、join()、sleep()方法在用的過(guò)程中被打斷(interupt),會(huì)拋出Interrupte dException)


boolean isInterrupted( )實(shí)例方法
判斷當(dāng)前線程是否被中斷(通過(guò)檢查中斷標(biāo)識(shí)位) 實(shí)例方法

static boolean interrupted( )靜態(tài)方法
判斷線程是否被中斷,并清楚當(dāng)前中斷狀態(tài),這個(gè)方法做了兩件事 第一件事 返回當(dāng)前線程的中斷狀態(tài)
第二件事 將當(dāng)前線程的中斷狀態(tài)設(shè)為false
原理:假設(shè)有兩個(gè)線程A、B,線程B調(diào)用了interrupt方法,這個(gè)時(shí)候我們連續(xù)調(diào)用兩次isInterrupted方法,第一次會(huì)返回true,然后這個(gè)方法會(huì)將中斷標(biāo)識(shí)位設(shè)置位false,所以第二次調(diào)用將返回false

比較靜態(tài)方法interrupted和實(shí)例方法isInterrupted 靜態(tài)方法interrupted將會(huì)清除中斷狀態(tài)(傳入的參數(shù)ClearInterrupted位true)實(shí)例方法isInterrupted則不會(huì)(傳入的參數(shù)ClearInterrupted為false)
如何使用中斷標(biāo)識(shí)停止線程
在需要中斷的線程中不斷監(jiān)聽(tīng)中斷狀態(tài),一旦發(fā)生中斷,就執(zhí)行型對(duì)于的中斷處理業(yè)務(wù)邏輯
三種中斷標(biāo)識(shí)停止線程的方式
- 通過(guò)一個(gè)volatile變量實(shí)現(xiàn)
- 通過(guò)AtomicBoolean
- 通過(guò)Thread類自帶的中斷API方法實(shí)現(xiàn)
public class InterruptDemo{
static volatile boolean isStop = false;
static AtomicBoolean atomicBoolean = new AtomicBoolean(false);
public static void m3(){
Thread t1 = new Thread(() -> {
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("-----isInterrupted() = true,程序結(jié)束。");
break;
}
System.out.println("------hello Interrupt");
}
}, "t1");
t1.start();
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(() -> {
t1.interrupt();//修改t1線程的中斷標(biāo)志位為true
},"t2").start();
}
/**
* 通過(guò)AtomicBoolean
*/
public static void m2(){
new Thread(() -> {
while(true)
{
if(atomicBoolean.get())
{
System.out.println("-----atomicBoolean.get() = true,程序結(jié)束。");
break;
}
System.out.println("------hello atomicBoolean");
}
},"t1").start();
//暫停幾秒鐘線程
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(() -> {
atomicBoolean.set(true);
},"t2").start();
}
/**
* 通過(guò)一個(gè)volatile變量實(shí)現(xiàn)
*/
public static void m1(){
new Thread(() -> {
while(true)
{
if(isStop)
{
System.out.println("-----isStop = true,程序結(jié)束。");
break;
}
System.out.println("------hello isStop");
}
},"t1").start();
//暫停幾秒鐘線程
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(() -> {
isStop = true;
},"t2").start();
}
}當(dāng)前線程的中斷標(biāo)識(shí)為true,是不是就立刻停止?
1、線程調(diào)用interrupt()時(shí)①. 如果線程處于正?;顒?dòng)狀態(tài),那么會(huì)將線程的中斷標(biāo)志設(shè)置位true,僅此而已。被設(shè)置中斷標(biāo)志的線程將繼續(xù)正常運(yùn)行,不受影響。所以,interrupt( )并不能真正的中斷線程,需要被調(diào)用的線程自己進(jìn)行配合才行
如果線程處于被阻塞狀態(tài)(例如處于sleep、wait、join等狀態(tài)),在別的線程中調(diào)用當(dāng)前線程對(duì)象的interrupt方法,那么線程立即被阻塞狀態(tài),并拋出一個(gè)InterruptedException異常)
2、中斷只是一種協(xié)同機(jī)制,修改中斷標(biāo)識(shí)位僅此而已,不是立即stop打斷
3 、sleep、wait 等方法拋出InterruptedException后,中斷標(biāo)識(shí)也被清空置為false,我們?cè)赾atch沒(méi)有通過(guò)調(diào)用th.interrupt( )方法再次將中斷標(biāo)識(shí)位設(shè)置位true,這就是導(dǎo)致無(wú)限循環(huán)了
總結(jié)
package com.bilibili.juc.interrupt;
import java.util.concurrent.TimeUnit;
/**
* @auther zzyy
* @create 2022-01-20 10:52
*/
public class InterruptDemo3
{
public static void main(String[] args)
{
Thread t1 = new Thread(() -> {
while (true)
{
if(Thread.currentThread().isInterrupted())
{
System.out.println(Thread.currentThread().getName()+"\t " +
"中斷標(biāo)志位:"+Thread.currentThread().isInterrupted()+" 程序停止");
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();//為什么要在異常處,再調(diào)用一次??
e.printStackTrace();
}
System.out.println("-----hello InterruptDemo3");
}
}, "t1");
t1.start();
//暫停幾秒鐘線程
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(() -> t1.interrupt(),"t2").start();
}
}
/**
* 1 中斷標(biāo)志位,默認(rèn)false
* 2 t2 ----> t1發(fā)出了中斷協(xié)商,t2調(diào)用t1.interrupt(),中斷標(biāo)志位true
* 3 中斷標(biāo)志位true,正常情況,程序停止,^_^
* 4 中斷標(biāo)志位true,異常情況, 就是t1過(guò)程中調(diào)用了sleep 、join 、 wait 方法 會(huì)拋出一個(gè) InterruptedException(中斷異常),
* 將會(huì)把中斷狀態(tài)將被清除,并且將收到InterruptedException 。中斷標(biāo)志位重新設(shè)置為false 導(dǎo)致無(wú)限循環(huán)
*
* 5 所以如果要線程中調(diào)用sleep 、join 、 wait 方法 需要在catch塊中,需要再次給中斷標(biāo)志位設(shè)置為true,2次調(diào)用停止程序才OK
*/到此這篇關(guān)于Java線程中斷機(jī)制interrupt、isInterrupted、interrupted方法詳解的文章就介紹到這了,更多相關(guān)Java線程中斷機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談java中為什么實(shí)體類需要實(shí)現(xiàn)序列化
下面小編就為大家?guī)?lái)一篇淺談java中為什么實(shí)體類需要實(shí)現(xiàn)序列化。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05
PL/SQL實(shí)現(xiàn)JAVA中的split()方法的例子
這篇文章主要介紹了PL/SQL實(shí)現(xiàn)JAVA中的split()方法的例子的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07
MyBatis-Plus批量操作SQL日志不打印問(wèn)題的解決方案
在使用 MyBatis-Plus 的?saveBatch()?和?updateBatchById()?方法進(jìn)行批量數(shù)據(jù)操作時(shí),發(fā)現(xiàn)自定義的 Druid SQL 日志攔截器無(wú)法打印這些批量操作的 SQL 語(yǔ)句,導(dǎo)致調(diào)試和問(wèn)題排查困難,本文給大家該問(wèn)題的詳細(xì)解決方案,需要的朋友可以參考下2026-03-03
SpringBoot整合MybatisPlus的基本應(yīng)用指南
MyBatis-Plus ,簡(jiǎn)稱 MP,是一個(gè) MyBatis的增強(qiáng)工具,在 MyBatis 的基礎(chǔ)上只做增強(qiáng)不做改變,下面小編就來(lái)和大家介紹一下SpringBoot整合MybatisPlus的一些基本應(yīng)用吧2025-03-03
springboot3.0整合rabbitmq3.13的實(shí)現(xiàn)示例
本文主要介紹了springboot3.0整合rabbitmq3.13的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-09-09

