文档章节

JAVA 中interrupt、interrupted和isInterrupted的区别

我爱春天的毛毛雨
 我爱春天的毛毛雨
发布于 09/18 22:44
字数 1634
阅读 8
收藏 0

首先,我们说明下三个方法的功能

  • interrupt() 向当前调用者线程发出中断信号
  • isinterrupted() 查看当前中断信号是true还是false
  • interrupted() 是静态方法,查看返回当前中断信号并将中断信号复位

interrupt()方法,能够将处于阻塞状态或等待状态(如wait()、 sleep() 、join()方法)的线程从阻塞状态跳出

今天在看到Thread类的isInterrupted方法可以获取线程的中断状态:

于是写了个例子想验证一下:

public class Interrupt {
	public static void main(String[] args) throws Exception {
		Thread t = new Thread(new Worker());
		t.start();
		
		Thread.sleep(200);
		t.interrupt();
		
		System.out.println("Main thread stopped.");
	}
	
	public static class Worker implements Runnable {
		public void run() {
			System.out.println("Worker started.");
			
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				System.out.println("Worker IsInterrupted: " + 
						Thread.currentThread().isInterrupted());
			}
			
			System.out.println("Worker stopped.");
		}
	}
}

内容很简答:主线程main启动了一个子线程Worker,然后让worker睡500ms,而main睡200ms,之后main调用worker线程的interrupt方法去中断worker,worker被中断后打印中断的状态。下面是执行结果:

Worker started.
Main thread stopped.
Worker IsInterrupted: false
Worker stopped.

Worker明明已经被中断,而isInterrupted()方法竟然返回了false,为什么呢?
 

在stackoverflow上搜索了一圈之后,发现有网友提到:可以查看抛出InterruptedException方法的JavaDoc(或源代码),于是我查看了Thread.sleep方法的文档,doc中是这样描述这个InterruptedException异常的:

InterruptedException - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.  

注意到后面这句“当抛出这个异常的时候,中断状态已被清除”。所以isInterrupted()方法应该返回false。可是有的时候,我们需要isInterrupted这个方法返回true,怎么办呢?这里就要先说说interrupt, interrupted和isInterrupted的区别了:

interrupt方法是用于中断线程的,调用该方法的线程的状态将被置为"中断"状态。注意:线程中断仅仅是设置线程的中断状态位,不会停止线程。需要用户自己去监视线程的状态为并做处理。支持线程中断的方法(也就是线程中断后会抛出InterruptedException的方法,比如这里的sleep,以及Object.wait等方法)就是在监视线程的中断状态,一旦线程的中断状态被置为“中断状态”,就会抛出中断异常。

interrupt() merely sets the thread's interruption status. Code running in the interrupted thread can later poll the interrupted status to see if it has been requested to stop what it is doing 

再来看看interrupted方法的实现:

public static boolean interrupted() {  
    return currentThread().isInterrupted(true);  
}  

和isInterrupted的实现:

public boolean isInterrupted() {  
    return isInterrupted(false);  
} 

这两个方法一个是static的,一个不是,但实际上都是在调用同一个方法,只是interrupted方法传入的参数为true,而inInterrupted传入的参数为false。那么这个参数到底是什么意思呢?来看下这个isInterrupted(boolean)方法的实现:

/** 
 * Tests if some Thread has been interrupted.  The interrupted state 
 * is reset or not based on the value of ClearInterrupted that is 
 * passed. 
 */  
private native boolean isInterrupted(boolean ClearInterrupted);  

这是一个native方法,看不到源码没有关系,参数名字ClearInterrupted已经清楚的表达了该参数的作用----是否清除中断状态。方法的注释也清晰的表达了“中断状态将会根据传入的ClearInterrupted参数值确定是否重置”。所以,静态方法interrupted将会清除中断状态(传入的参数ClearInterrupted为true),而实例方法isInterrupted则不会(传入的参数ClearInterrupted为false)。

回到刚刚的问题:很明显,如果要isInterrupted这个方法返回true,通过在调用isInterrupted方法之前再次调用interrupt()方法来恢复这个中断的状态即可:

public class Interrupt  {  
    public static void main(String[] args) throws Exception {  
        Thread t = new Thread(new Worker());  
        t.start();  
          
        Thread.sleep(200);  
        t.interrupt();  
          
        System.out.println("Main thread stopped.");  
    }  
      
    public static class Worker implements Runnable {  
        public void run() {  
            System.out.println("Worker started.");  
              
            try {  
                Thread.sleep(500);  
            } catch (InterruptedException e) {  
                Thread curr = Thread.currentThread();  
                //再次调用interrupt方法中断自己,将中断状态设置为“中断”  
                curr.interrupt();  
                System.out.println("Worker IsInterrupted: " + curr.isInterrupted());  
                System.out.println("Worker IsInterrupted: " + curr.isInterrupted());  
                System.out.println("Static Call: " + Thread.interrupted());//clear status  
                System.out.println("---------After Interrupt Status Cleared----------");  
                System.out.println("Static Call: " + Thread.interrupted());  
                System.out.println("Worker IsInterrupted: " + curr.isInterrupted());  
                System.out.println("Worker IsInterrupted: " + curr.isInterrupted());  
            }  
              
            System.out.println("Worker stopped.");  
        }  
    }  
}  

执行结果:

Worker started.  
Main thread stopped.  
Worker IsInterrupted: true  
Worker IsInterrupted: true  
Static Call: true  
---------After Interrupt Status Cleared----------  
Static Call: false  
Worker IsInterrupted: false  
Worker IsInterrupted: false  
Worker stopped. 

从执行结果也可以看到,前两次调用isInterrupted方法都返回true,说明isInterrupted方法不会改变线程的中断状态,而接下来调用静态的interrupted()方法,第一次返回了true,表示线程被中断,第二次则返回了false,因为第一次调用的时候已经清除了中断状态。最后两次调用isInterrupted()方法就肯定返回false了。

那么,在什么场景下,我们需要在catch块里面中断线程(重置中断状态)呢?
答案是:如果不能抛出InterruptedException(就像这里的Thread.sleep语句放在了Runnable的run方法中,这个方法不允许抛出任何受检查的异常),但又想告诉上层调用者这里发生了中断的时候,就只能在catch里面重置中断状态了。
以下内容来自:Dealing with InterruptedException

If you catch InterruptedException but cannot rethrow it, you should preserve evidence that the interruption occurred so that code higher up on the call stack can learn of the interruption and respond to it if it wants to. This task is accomplished by calling interrupt() to "reinterrupt" the current thread, as shown in Listing 3. 

如果捕捉到InterruptedException但不能重新抛出,则应保留中断发生的证据,以便调用堆栈上的较高层代码可以了解中断,并在需要时作出响应。这个任务是通过调用interrupt()来实现对当前线程的“重新中断”,如清单3所示。

Listing 3: Restoring the interrupted status after catching InterruptedException

public class TaskRunner implements Runnable {  
    private BlockingQueue<Task> queue;  
   
    public TaskRunner(BlockingQueue<Task> queue) {   
        this.queue = queue;   
    }  
   
    public void run() {   
        try {  
             while (true) {  
                 Task task = queue.take(10, TimeUnit.SECONDS);  
                 task.execute();  
             }  
         } catch (InterruptedException e) {   
             // Restore the interrupted status  
             Thread.currentThread().interrupt();  
         }  
    }  
}  

那么问题来了:为什么要在抛出InterruptedException的时候清除掉中断状态呢?
这个问题没有找到官方的解释,估计只有Java设计者们才能回答了。但这里的解释似乎比较合理:一个中断应该只被处理一次(你catch了这个InterruptedException,说明你能处理这个异常,你不希望上层调用者看到这个中断)。

本文转载自:https://blog.csdn.net/qpc908694753/article/details/61414495

共有 人打赏支持
我爱春天的毛毛雨
粉丝 3
博文 44
码字总数 102873
作品 0
鸡西
私信 提问
Java多线程之interrupt()的深度研究

原文地址:http://www.cnblogs.com/carmanloneliness/p/3516405.html 近期学习Java多线程的中断机制,网上的帖子说得很浅,并没深究其原理。看了Java源码,对Java的中断机制有了略深入的理解...

恶魔在江湖
2014/02/18
0
0
Java并发编程学习一:线程的概念以及使用

该篇文章作为自己并发学习的一个开始,首先介绍一下线程的概念以及使用。 讨论基于单核cpu进行 线程的意义 要了解线程的意义,首先先介绍一下进程,什么是进程?进程概念如下(摘自百度百科)...

JerryLin123
11/10
0
0
多线程编程读书笔记之线程中断的本质

Java试图提供过抢占式限制中断,但问题多多,例如已被废弃的Thread.stop、Thread.suspend和 Thread.resume等。另一方面,出于Java应用代码的健壮性的考虑,降低了编程门槛,减少不清楚底层机...

刘学炜
2012/07/03
0
0
Thread中interrupt()interrupted()和isInterrupted()的区别

在java线程中,线程的状态分为6种。官方文档的解释是: NEW:Thread刚刚new出来。 RUNNABLE:start方法已运行,所有条件都就绪。只等该线程获得CPU运行时间。 BLOCKED:等待进入临界区。 WA...

jiangmitiao
2015/09/01
0
0
「阿里面试系列」面试加分项,从JVM层面了解线程的启动和停止

文章简介 这一篇主要围绕线程状态控制相关的操作分析线程的原理,比如线程的中断,线程的通信等,内容比较多,可能会分两篇文章 阿里面试系列导读:关注我的技术公众号【架构师修炼宝典】一周...

Java架构资源分享
12/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

mybatis批量update操作的写法,及批量update报错的问题解决方法

mybatis的批量update操作写法很简单,如下: 如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿...

编程SHA
31分钟前
3
0
EOS怎样删除钱包

在使用Eos的keosd钱包软件时,如果要删除EOS中指定名称的钱包,最简单的办法是 直接删除钱包文件,不过在删除钱包之前,需要先停止钱包软件的运行。 学习EOS应用开发要选这个:【EOS智能合约...

汇智网教程
38分钟前
7
0
Java语言快速实现简单MQ消息队列服务

使用 JAVA 语言自己动手来写一个MQ (类似ActiveMQ,RabbitMQ) 主要角色 首先我们必须需要搞明白 MQ (消息队列) 中的三个基本角色 ProducerBrokerConsumer 整体架构如下所示 自定义协议 首...

微笑向暖wx
47分钟前
5
0
ES5和ES6那些你必须知道的事儿

  ES5和ES6那些你必须知道的事儿      ES5新增的东西      一、数组方法      1、forEach      用途:遍历,循环      对于空数组不会执行回调函数      复制代码...

SEOwhywhy
今天
11
0
转:[windows]DOS批处理添加任务计划

[windows]DOS批处理添加任务计划 博客分类: Windows 转自:http://gwmold.blog.163.com/blog/static/1553319892010117113457232/ 自动创建每周运行一次的计划任务 创建计划任务可用at,sch...

SamXIAO
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部