浅谈Java线程Thread之interrupt中断解析
作者:Ihesong 发布时间:2023-07-19 09:25:11
这一篇我们说说Java线程Thread的interrupt中断机制。
中断线程
线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序本身。线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true)。它并不像stop方法那样会中断一个正在运行的线程。
判断线程是否被中断
判断某个线程是否已被发送过中断请求,请使用Thread.currentThread().isInterrupted()方法(因为它将线程中断标示位设置为true后,不会立刻清除中断标示位,即不会将中断标设置为false),而不要使用thread.interrupted()(该方法调用后会将中断标示位清除,即重新设置为false)方法来判断,下面是线程在循环中时的中断方式:
while(!Thread.currentThread().isInterrupted() && more work to do){
do more work
}
interrupt之中断状态标记
interrupt中断机制中有如下方法:
Thread.interrupt(),设置当前中断标记为true(类似属性的set方法)
Thread.isInterrupted(),检测当前的中断标记(类似属性的get方法)
Thread.interrupted(),检测当前的中断标记,然后重置中断标记为false(类似属性的get方法+set方法)
因此interrupt中断机制并不是真正的将当前线程中断,而是一个中断标记的变化。我们先用例子来测试一下。
public class InterruptTest {
//这里用来打印消耗的时间
private static long time = 0;
private static void resetTime(){
time = System.currentTimeMillis();
}
private static void printContent(String content){
System.out.println(content + " 时间:" + (System.currentTimeMillis() - time));
}
public static void main(String[] args) {
test1();
}
private static void test1(){
Thread1 thread1 = new Thread1();
thread1.start();
//延时3秒后interrupt中断
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread1.interrupt();
printContent("执行中断");
}
private static class Thread1 extends Thread{
@Override public void run() {
resetTime();
int num = 0;
while (true){
if(isInterrupted()){
printContent("当前线程 isInterrupted");
break;
}
num++;
if(num % 100 == 0){
printContent("num : " + num);
}
}
}
}
}
以上代码是开启一个Thread1线程,在Thread1线程的while循环中不断对num加1,每到100的倍数打印一次(防止打印太快)。然后主线程在sleep了3000毫秒后,调用Thread1线程的interrupt方法。那么我们看看输出结果:
intterupt中断
可以看到,在耗时3000毫秒左右,也就是主线程sleep之后执行thread1.interrupt();后,Thread1线程停止了,而Thread1线程的停止是因为while循环中的isInterrupted方法返回了true,所以break退出了while循环,也就是说interrupt和isInterrupted在这里起到的作用就相当于setXX和getXX的作用,维护着一个boolean变量。
interrupt之中断异常处理
当然interrupt机制并不仅仅是一个中断状态位的变化和检测,它还可以进行中断异常的处理。我们知道Thread.sleep()方法需要捕获中断异常,那接下来我们往其中添加一个sleep延时试试
while (true){
if(isInterrupted()){
printContent("当前线程 isInterrupted");
break;
}
num++;
//sleep一下
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(num % 100 == 0){
printContent("num : " + num);
}
}
我们再看看输出结果:
intterupt中断
这里我们会发现,sleep睡眠之后,输出的num值明显小了好多(没睡眠时num都达到10亿的大小了,看来CPU执行简单运算还是非常快的),哈哈,不过这不是重点,重点是是看到输出了一个异常,还有就是输出异常后,isInterrupted输出返回false,Thread1线程又继续执行下去了,并没有退出while循环。那么这是为什么呢?我们只是加了一个sleep睡眠而已。
如果Thread1线程中有执行需要捕获InterruptedException异常的操作,比如Thread的sleep,join方法,Object的wait,Condition的await等,它是强制需要捕获InterruptedException异常的,那么当thread1.interrupt方法调用之后,它会给thread1线程抛出一个InterruptedException异常,那么在while循环中,就能捕获到这个异常然后这个异常抛出之后,又会马上将线程中断标识重置为false,因此在下次的while循环中判断isInterrupted时,它是false,也就不会break,然后while循环会一直执行下去。
因此interrupt()方法会根据thread线程中的run方法里是否有必须捕获InterruptedException异常的代码,而做出不同操作:
如果没有必须捕获InterruptedException异常的代码(比如Thread.sleep()),则isInterrupted()会返回true,此时可以在isInterrupted的判断中处理中断变化。
如果有必须捕获InterruptedException异常的代码(比如Thread.sleep()),则会抛出InterruptedException异常,并进行捕获,同时重置isInterrupted为false,此时得在异常捕获中处理中断变化。
interrupt的应用场景
通常interrupt适用于在线程执行中的循环标记判断,例如
while(!isInterrupted()){
...
}
但是如果在本次循环中出现阻塞了,那么线程就无法判断下次的isInterrupted标记,那么即便调用了interrupt()方法也无法退出循环,也就无法退出线程。例如
while(!isInterrupted()){
...
while(true){
//线程卡在这里了,则无法响应interrupte机制了
}
}
这样的话,interrupt就没辙了,线程会一直执行下去,不会被中断停止。
测试例子查看 我的GitHub--JavaTest
来源:https://www.jianshu.com/p/7f1071293a18
猜你喜欢
- 简介对于一个APP来说,肯定会有一个AppBar,这个AppBar一般包含了APP的导航信息等。虽然我们可以用一个固定的组件来做为AppBa
- 一、方法这里我们用两种方法来实现跑马灯效果,虽然实质上是一种实质就是:1、TextView调出跑马灯效果2、TextView获取焦点&nbs
- 讲这个例子前,咱们先来看一个简单的程序:字符串数组实现数字转字母:#include <stdio.h>#include <
- 当你在开发flutter应用的时候,有时会需要调用native的api,往往遇到flutter并没有相应的package, 这时候flutt
- 一、什么是iText?在企业的信息系统中,报表处理一直占比较重要的作用,iText是一种生成PDF报表的Java组件。通过在服务器端使用Js
- 这篇文章主要介绍了spring boot如何实现切割分片上传,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需
- 现如今打开一个 App,比如头条、微博,都会有长列表,随着我们不断地滑动,视窗内的内容也会不断地更新。今天就用 Flutter 实现一下这种
- MediaQuery通常情况下,不会直接将MediaQuery当作一个控件,而是使用MediaQuery.of获取当前设备的信息,用法如下:
- 背景实际开发中,常常需要将比较复杂的 JSON 字符串转换为对应的 Java 对象。这里记录下解决方案。如下所示,是入侵事件检测得到的 JS
- 本文实例讲述了C#获取网页源代码的方法。分享给大家供大家参考。具体如下:public string GetPageHTML(string u
- Navigator 的 push 和 pop方法Navigator 导航器的 push 和 pop 方法可以携带参数在页面间传递,其他变形的
- 井字棋游戏要求在3乘3棋盘上,每行都相同或者每列都相同再或者对角线相同,则胜出.因此我们可以使用一个二维数组来表示棋盘,判断胜负只需要判断数
- 本文实例为大家分享了android自定义环形对比图的具体代码,供大家参考,具体内容如下1.首先在res/values里创建一个attr.xm
- 最近正式入坑Flutter,首先从环境搭建开始,看了网上好多关于Windows环境搭建的资料,基本都是按官方文档写的,看完的感受是,还不如直
- 1)字符串操作 strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 strcat(p, p1)
- 本文的目的是要实现左右滑动的指引效果。那么什么是指引效果呢?现在的应用为了有更好的用户体验,一般会在应用开始显示一些指引帮助页面,使用户能更
- java字段值为null,不返回该字段类上打注解@JsonSerialize(include = JsonSerialize.Inclusi
- Pom依赖<parent> <groupId>org.springframework.bo
- 最近“全网域(Web Scale)”一词被炒得火热,人们也正在通过扩展他们的应用程序架构来使他们的系统变得更加“全网域”。但是究竟什么是全网
- 一直使用Eclipse环境开发Android,也尝鲜使用过Android Studio去开发,各种IDE配合Android SDK及SDK原