Java线程中断 阻塞 InterruptedException
- 线程切换:线程处于可运行的状态,只是还没有获取CPU时间片,如yield方法
- 线程阻塞:线程请求资源等不满足,进入阻塞状态,无法运行
- 线程中断:操作系统中断是保存现场,进行中断处理。而Java线程中断仅仅是一个状态,中断标志位设置为true,线程完全可以不理睬继续执行,也可以响应这个中断或者抛出异常,取决于线程的动作,中断仅仅是一个通知,提供了一种线程控制机制
线程中断
一般的,中断只是一个通知,当调用线程的interrupt方法的时候,仅仅把中断标志位设置位ture,不发生其他的任何事。线程内部可以写代码,用isInterrupted 或者interrupted 去轮询判断是否被设置位中断状态,如果是,可以进行一些处理,当然也可以忽略,完全是线程自己的行为。比如:
public class InterruptTest {
public static void main(String[] args) throws InterruptedException{
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()) {
System.out.println("执行。。。");
}
}
});
thread.start();
Thread.sleep(1);
thread.interrupt();//线程可以完全不理睬这个中断,也可以在代码中对这个中断响应
}
}
上述代码执行结果是调用 thread.interrupt() 方法之前,线程执行,调用之后, 线程响应这个中断,退出执行。
isInterrupted 和 interrupted 区别是:
isInterrupted 是个非静态方法,检验线程中断状态是否是true,是的话就返回true,否则返回false
interrupted 是Thread类的静态方法,但是会清除中断标志,把中断标志设置为fasle
参考:
每个线程都有一个与之相关联的 Boolean 属性,用于表示线程的中断状态(interrupted status)。中断状态初始时为 false;当另一个线程通过调用
Thread.interrupt()
中断一个线程时,会出现以下两种情况之一。如果那个线程在执行一个低级可中断阻塞方法,例如Thread.sleep()
、Thread.join()
或Object.wait()
,那么它将取消阻塞并抛出InterruptedException
。否则,interrupt()
只是设置线程的中断状态。 在被中断线程中运行的代码以后可以轮询中断状态,看看它是否被请求停止正在做的事情。中断状态可以通过Thread.isInterrupted()
来读取,并且可以通过一个名为Thread.interrupted()
的操作读取和清除。中断是一种协作机制。当一个线程中断另一个线程时,被中断的线程不一定要立即停止正在做的事情。相反,中断是礼貌地请求另一个线程在它愿意并且方便的时候停止它正在做的事情。有些方法,例如
Thread.sleep()
,很认真地对待这样的请求,但每个方法不是一定要对中断作出响应。对于中断请求,不阻塞但是仍然要花较长时间执行的方法可以轮询中断状态,并在被中断的时候提前返回。 您可以随意忽略中断请求,但是这样做的话会影响响应。中断的协作特性所带来的一个好处是,它为安全地构造可取消活动提供更大的灵活性。我们很少希望一个活动立即停止;如果活动在正在进行更新的时候被取消,那么程序数据结构可能处于不一致状态。中断允许一个可取消活动来清理正在进行的工作,恢复不变量,通知其他活动它要被取消,然后才终止。
interrupt()方法不能直接中断线程,而是为其设置一个中断标志。对于非阻塞任务,我们可以调用interrupted()方法来检查interrupt()方法是否被调用过(然后便可以进行自定义中断处理),并且这个方法还会将中断标志清空掉,这样也就保证了中断处理只进行一次。对于阻塞任务,我们就要通过抛出InterruptedException进行处理了,同样地,这个异常抛出的同时会重置中断标志。因此当任务较为复杂的时候,我们需要谨慎处理,保证中断经由单一的异常或是interrupted()处理掉。
阻塞可中断
阻塞方法可能因为等不到所等的事件而无法终止,因此令阻塞方法可取消 就非常有用(如果长时间运行的非阻塞方法是可取消的,那么通常也非常有用)。可取消操作是指能从外部使之在正常完成之前终止的操作。
如果线程在执行一个低级可中断阻塞方法,例如 Thread.sleep()
、 Thread.join()
或 Object.wait()
,会监听中断的状态,如果当前线程被中断,它将取消阻塞并抛出 InterruptedException
,同时会清除中断状态。InterruptedException
是对上层调用的一个通知,表示:我取消了阻塞状态。
同时,如果一个线程处于reentrantLock.tryLock(longtimeout, TimeUnit unit) 和 reentrantLock.lockInterruptibly()阻塞队列中的时候,是可以响应中断抛出异常的。
阻塞不可中断
有一种情况是线程不能被中断的,就是调用synchronized关键字和reentrantLock.lock()获取锁的过程。当线程没有获取锁,等待获取锁的时候,会在阻塞队列中,此时线程不可中断,也不会响应中断。所以说:
synchronized 是不可中断的,是指在阻塞队列中的没有获取锁线程不会理睬中断。
总结
Java线程中断只是一种线程控制机制,线程可以有选择地处理或者忽略中断。InterruptedException是对中断进行通知和重置状态。