Java Concurrent之 java线程中断,
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时,不应捕捉后将其“吃掉” 应该继续向上层 抛出。
相关文章
- 暂无相关文章
用户点评