【并发编程】Java中断机制——协作式中断含义及应用

原创 2015年11月19日 04:20:11

一、概要

本文试图对以下内容进行阐述和说明:

    1. Java中断是协作式中断,“协作式中断”的含义;

    2. Java中断并不是立即响应,那么线程什么时候中断?又在什么时候响应中断?如何响应中断?


二、详解

1. 协作式中断的含义

    借鉴INFOQ文章中的例子(链接:点击打开链接),协作式中断就像逢年过节回家,长辈总会告诫我们出门在外要照顾好自己,我们收到告诫后心里面就会记下来,但并不是立即就好好照顾自己(因为此时并不需要),而是等到我们出现需要照顾自己的场景的时候(譬如在外生病啦、孤独啦等等),回想到长辈的告诫,才去响应这个告诫,然后自己对自己好一点,去买平时舍不得买的东西,吃平时舍不得吃的东西。这段话有两个点,一个是通过长辈告诫我们,另一个是在恰当的场景下我们才会去响应并执行这个告诫,但是最终响应并执行这个告诫始终是我们自己<标记1>

    由此,可以引出java协作式中断的含义,辅助参看下面一段代码<标记2>

public static void main(String[] args) {
	// 初始化一个线程
	Thread thread = new Thread("中断") {
		public void run() {
			try {
				/**
				 * 注意:sleep方法揭示了java线程何时、如何响应中断
				 * public static native void sleep(long millis) throws InterruptedException;
				 */
				Thread.sleep(600 * 1000);
			} catch (InterruptedException e) {
				/**
				 * 结果为true,因此当前线程thread中断状态标志位已经置位
				 */
				if(Thread.interrupted())
					System.out.println("当前线程状态:中断");
				e.printStackTrace();
			}
		};
	};
	/**
	 * 当“中断”线程启动以后,此时系统中存在两个线程
	 * 1. main线程;
	 * 2. “中断”线程;
	 */
	thread.start();
	// 为了通过工具分析线程状态,这里将主线程暂停一分钟,方便观察
	try {
		Thread.sleep(10*1000);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	/**
	 * 在主线程中中断(告诫)thread,此时thread修改了中断标志位,但是并没有立即响应
	 */
	thread.interrupt();
	/**
	 * 输出false,因为主线程此时并没有被中断
	 */
	System.out.println(Thread.interrupted());
}

    Thread类中与中断直接相关的方法有四个,如下图所示<标记3>


    interrupt方法将会设置线程中断状态,表示该线程中断,但是并不是立即中断(因为还没有响应,下一节介绍),而是该线程在“合适”的时候;interrupted方法是一个静态方法,该方法会返回当前线程的中断状态并重置状态为false,当线程中断标志位为true时,调用inerrupted方法返回true并将标志位设置为false,再次调用interrupted的时候,将返回false(因为第一次调用的时候已经重置中断标志位了);而isInterrupted方法则返回线程的中断标志位;isInterrupted(boolean)是一个native方法,返回线程中断状态,其中传入的boolean参数用于控制是否需要重置线程中断标志位,interrupted和isInterrupted方法均基于该方法(逻辑简单,请自行参见源码)。

    结合三个标记的材料,可以对java协作式中断进行分析。

    1. 我们在主线程中调用thread的interrupt方法重置了thread的中断状态,此时thread记住了重置的中断状态(对应的是长辈对我们的告诫,然后我们将告诫记在心中),但是此时线程并没有立即中断;

    2. 最终当thread的run方法执行到sleep的时候,thread会去检查这个中断标志位,如果Thread.interrupted()为true,则throw new InterruptedExctption(),注意,interrupted方法会重置中断标志位(重点:最终是否响应中断,在于我们自己写的代码中是否有中断状态的判断,如果没有主动写中断状态判断的代码,也没有调用已经写了中断状态判断的代码,则线程永远不会响应中断,这对应着标志1中“恰当的场景和最终响应并执行告诫的永远是我们自己”);

    值得商榷的是,是否一定要在其它线程中调用thread的中断方法。可以把主线程中thread.interrupt()方法撤掉,然后再thread的run方法中来写,在sleep之前this.interrupt()一样可以达到中断thread的效果,不过这样的场景并不多见,因此不做更深的讨论。

2. 中断响应

   重点:最终线程是否响应中断,在于代码中是否有中断状态的判断,如果既没有主动写中断状态判断的代码,也没有调用已经写了中断状态判断的代码,则线程永远不会响应中断。

    所以,java协作式中断的响应,在于代码中中断方法和中断异常的配合,要么自己主动写,要么调用JDK中已经写好了的代码。要想知道JDK中哪些常见代码可以响应中断,打开Thread类和Object类,搜索方法签名抛出中断异常InterruptedException即可。

/**
 * public static native void sleep(long millis) throws InterruptedException
 * public final void join() throws InterruptedException
 * public final native void wait(long timeout) throws InterruptedException;
 */
    要想主动写中断判断的代码来使用java协作式中断机制,四个中断方法(JDK中sleep、join和wait采用类似interrupted方法)和一个中断异常搭配即可,参看如下示例代码。

package cn.wxy.thread;

import java.util.concurrent.TimeUnit;

public class JavaInterrupted extends Thread {
	public void run() {
		try {
			mySleep(TimeUnit.SECONDS.toSeconds(1)); // 线程执行到这里的时候,将会成为time_wait状态,此时释放执行权(不释放锁),当中断方法被调用后,线程的time_wait状态被中断
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Thread.sleep(long)方法中中断逻辑的代码
	 * @param seconds
	 * @throws InterruptedException
	 */
	private static void mySleep(long seconds) throws InterruptedException {
		/**
		 * Thread.sleep方法:OS睡眠逻辑+中断判断代码,本处省略OS睡眠逻辑的代码
		 */
		if(Thread.interrupted())
			throw new InterruptedException();
	}
}
    所以,要想让你的程序响应中断,只需要在你的代码中通过interrupted方法和InterruptedException异常结合即可。因为interrupted方法会清除线程的中断状态,因此如果想继续保持中断状态,则在异常处理中继续调用interrupt方法即可。


附注:

    本文如有错漏,烦请不吝指正,谢谢!

版权声明:本文为原创文章,转载时请注明出处;文章如有错漏,烦请不吝指正,谢谢!

【并发编程】CPU流水线的探秘之旅

CPU流水和流水线科普文章,隶属程序猿的内功修为

【IO】getResourceAsStream小记

java.lang.Class.getResourceAsStream和java.lang.ClassLoader.getResourceAsStream

java并发编程—— 六 进程协作:阻塞队列\wait() notify()\ Condition

进程协作的三种常用方式wait()&¬ifyAll()要点: wait()中释放该对象的对象锁 notify() notifyAll() wait() 均是Object方法 noti...
  • lemon89
  • lemon89
  • 2016年03月24日 23:47
  • 1591

Java线程通信与协作的解决方案——等待/通知机制

线程与线程之间不是相互独立的个体,它们彼此之间需要相互通信和协作,最典型的例子就是生产者-消费者问题:有一个商品队列,生产者想队列中添加商品,消费者取出队列中的商品;显然,如果队列为空,消费者应该等待...

Java并发(二):线程协作 生产者/消费者、线程中断、线程让步、线程睡眠、线程合并

线程协作-生产者/消费者上一篇讲述了线程的互斥(同步),但是在很多情况下,仅仅同步是不够的,还需要线程与线程协作(通信),生产者/消费者问题是一个经典的线程同步以及通信的案例。该问题描述了两个共享固定...

Java并发编程:中断机制

之前讲解Thread类中方法的时候,interrupt()、interrupted()、isInterrupted()三个方法没有讲得很清楚,只是提了一下。现在把这三个方法同一放到这里来讲,因为这三个...

java并发编程-线程间协作的两种方式:wait、notify、nitifyAll和Condition

1.问题引入          线程之间也是需要协作的,比如生产者-消费者模型:当队列满时, 生产者需要等待队列中有空间才能够向里面放入物品,而在等待的时间内,生产者必须释放对资源(队列)的占有权。因...
  • cpf2016
  • cpf2016
  • 2015年01月29日 09:52
  • 263

JAVA并发编程-线程间协作(Object监视器方法与Condition)

JAVA并发编程第一篇     说到线程间协作,不得不提到经典的生产者与消费者模型:有一个商品队列,生产者想队列中添加商品,消费者取出队列中的商品;显然,如果队列为空,消费者应该等待生产者产生商品...

java并发编程(13)--线程间协作的两种方式:wait、notify、notifyAll和Condition

本文转载自:http://www.cnblogs.com/dolphin0520/p/3920385.html 尊重原创在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作。比如说最经...
  • Mrzhoug
  • Mrzhoug
  • 2016年05月04日 21:56
  • 306

Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition 原文地址:http://www.cnblogs.com/dolphin0520/p/39203...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【并发编程】Java中断机制——协作式中断含义及应用
举报原因:
原因补充:

(最多只允许输入30个字)