`

Java Concurrent之 java线程中断

 
阅读更多

  中断(Interrupt):java中的每个线程自身都维护这一个boolean型的中断标识(JVM帮我们搞定了),唯有通过Thread.interrupt()方法可以将其置为true,(我们可以通过interrupted()/isInterrupted()方法来判断线程是否处于中断状态,需要注意的是:interrupted()方法会重置线程的中断状态,即将标识置为false),线程遇到中断,并不会立即停止,而且线程会是死亡、等待新的任务亦或是无视中断继续运行,这都还取决于程序本身的处理。

   其实,java也试图提供过抢占式中断,像已经被deprecated的Thread.stop()、Thread.suspend()、Thread.resume等,都问题多多。现在java的线程调度采用协作式中断,原理很简单:轮询某个表示中断的标记。

 

/**
 * @author Sonicery_D
 * @date 2014年12月23日
 * @version 1.0.0
 * @description
 **/
public class TestInterrupt implements Runnable{

	volatile boolean isInterrupted = false;
	@Override
	public void run() {
		while(true){
			if(isInterrupted){
				System.out.println("isInterrupted ............");
				break;
			}
			System.out.println("test---Interrupt---"+System.currentTimeMillis());
		}
	}

	
	public static void main(String[] args){
		TestInterrupt testInterrupt = new TestInterrupt();
		Thread t = new Thread(testInterrupt);
		t.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("发起中断...");
		testInterrupt.isInterrupted = true;
	}
}

 但是当我们遇到阻塞方法时,上述的代码就束手无策了。如Object.wait()/Thread.sleep()/Thread.join()等阻塞方法

 

  注意通常我们调用Thread.interrupt()方法时无法立即引发中断的,它还是设置了JVM内部维护的中断标志,通过这个思路,应用程序可以检查中断标志来做一些特殊操作或者忽略掉中断。

 

/**
 * @author Sonicery_D
 * @date 2014年12月23日
 * @version 1.0.0
 * @description
 **/
public class TestInterrupt implements Runnable{

	volatile boolean isInterrupted = false;
	@Override
	public void run() {
		while(true){
			if(Thread.currentThread().isInterrupted()){
				System.out.println("isInterrupted ............");
				break;
			}
			System.out.println("test---Interrupt---"+System.currentTimeMillis());
		}
	}

	
	public static void main(String[] args){
		TestInterrupt testInterrupt = new TestInterrupt();
		Thread t = new Thread(testInterrupt);
		t.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("发起中断...");
		t.interrupt();//调用Thread.interrupt()是无法立即引发中断 只是将JVM内部维护的中断标志置为true
//		testInterrupt.isInterrupted = true;
	}
}

  在执行线程调度的阻塞调用时(Object.wait()/Thread.sleep()/Thread.join())如果发生中断,被阻塞线程会“尽可能快的”抛出InterruptedException。因此我们可以对阻塞时的中断作出处理。

 

 

public class TestInterrupt implements Runnable{

	volatile boolean isInterrupted = false;
	@Override
	public void run() {
		while(!isInterrupted){
			try {
				Thread.sleep(5000);
				System.out.println("test---Interrupt---"+System.currentTimeMillis());
			} catch (InterruptedException e) {
				e.printStackTrace();
				System.out.println("occur the interrupted ... ...");
			}
		}
	}

	
	public static void main(String[] args){
		TestInterrupt testInterrupt = new TestInterrupt();
		Thread t = new Thread(testInterrupt);
		t.start();
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("发起中断...");
		testInterrupt.isInterrupted = true;
		t.interrupt();
	}
}

   我们也可以不使用volatile修饰的可见变量,使用Thread.interrupted()/Thread.isInterrupted()来判断是否需要中断

 

 

/**
 * @author Sonicery_D
 * @date 2014年12月23日
 * @version 1.0.0
 * @description
 **/
public class TestInterrupt implements Runnable{

	@Override
	public void run() {
		while(true){//Thread.interrupted() 会将中断状态重置为false
			try {
				test();
			} catch (InterruptedException e) {//注意这里因为上层再没有需要判断中断的方法,所以我并没有继续向上层方法调用栈抛异常 
				e.printStackTrace();
				System.out.println("occur the interrupted ... ...");
break;
			}
		}
	}

	public void test() throws InterruptedException{
		if(Thread.interrupted()){
			throw new InterruptedException("test 操作发生了中断 ... ...");
		}
	}
	public static void main(String[] args){
		TestInterrupt testInterrupt = new TestInterrupt();
		Thread t = new Thread(testInterrupt);
		t.start();
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("发起中断...");
		if(t.isAlive())
		t.interrupt();
	}
}

   在任务和线程分离的框架中,任务通常不能提前知道会被那个线程执行,也就不知道具体调用线程处理中断的策略,故 在任务被设置了中断标志后并不能保证任务会被取消。

 

  一般来说除非你知道线程的中断策略,否则我们不应该中断它。例如,我们不应直接调用Executor之类的框架线程的interrupt方法,应该调用类似Future.cancel方法来取消任务。

   另外,任务代码不应该猜测中断对执行线程的含义。一般代码遇到InterruptedException时,不应捕捉后将其“吃掉” 应该继续向上层 抛出。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics