线程中断机制

前言

之前我们捋清楚了线程中的sleep(),wait(),join()等方法,这里我们再来学习下java中的线程中断机制。中断是一种协作机制。当一个线程中断另一个线程时,被中断的线程不一定要立即停止正在做的事情。相反,中断是礼貌地请求另一个线程在它愿意并且方便的时候停止它正在做的事情。有些方法,例如 Thread.sleep(),很认真地对待这样的请求,但每个方法不是一定要对中断作出响应。对于中断请求,不阻塞但是仍然要花较长时间执行的方法可以轮询中断状态,并在被中断的时候提前返回。 您可以随意忽略中断请求,但是这样做的话会影响响应。

为何放弃stop

我们先从sleep方法开始介绍。我们都知道,如果我们想要调用thread.sleep()方法,必须要求我们catch一个InterruptedException。这个InterruptedException异常,就是由线程中断造成的。
当线程运行到一个不可控制的状态的时候,我们想尝试结束他,这个时候,使用线程的stop方法或suspend方法(这两个都是经典线程方法),但都是非常不安全的,比如调用stop方法,该方法会立刻,马上终止当前线程,就有可能造成本来还在该线程正常锁同步的内容突然破坏,让本该保护的变量被其他线程可见。虽然这个时候会抛出一个特殊的ThreadDeath()异常,但这个异常是没法被正常处理的,就有可能让其他线程消费到错误的数据。所以该方法被标记为过期。
简单的例子,比如A线程正在执行代码:

synchronized {
    x = 3;
    y = 4;
}

本来代码块是synchronized标记的,保证x和y总是同时能被赋值,但假如A线程执行到x=3代码的时候,突然调用了stop方法,A线程立刻被杀死,导致出现了一个潜在的不安全的数据。这个就是stop的问题所在。

interrupt又该怎么用

interrupt方法,是告诉线程,我需要中断你,但是一定注意,该方法调用之后,线程并不会立刻终止,而是在合适的时机终止。什么时机呢?Java的处理判定机制为:
机制一:如果该线程处在可中断状态下,(调用了xx.wait(),或者Thread.sleep()等特定会发生阻塞的api),那么该线程会立即被唤醒,同时会收到一个InterruptedException,如果是阻塞在io上,对应的资源会被关闭。
机制二:如果该线程处在不可中断状态下,就是没有调用上述api,那么java只是设置一下该线程的interrupt状态,其他事情都不会发生,如果该线程之后会调用行数阻塞API,那到时候线程会马会上跳出,并抛出InterruptedException,接下来的事情就跟第一种状况一致了。如果不会调用阻塞API,那么这个线程就会一直执行下去。除非你就是要实现这样的线程,一般高性能的代码中肯定会有wait(),yield()之类出让cpu的函数,不会发生后者的情况。

  • 中断处于运行中的线程;
    线程中断机制_第1张图片
    线程中断机制_第2张图片
    上面的图片里,在main方法启动MyThread1线程, 线程正常执行,3秒之后,对MyThread1线程发起中断请求。在MyThread1线程run方法中,循环检查中断标识,Thread.currentThread().isInterrupted()一但监测到线程中断请求,立马终止循环,结束线程。
  • 中断处于堵塞的线程

线程休眠等待条件满足,当条件提前满足,马上中断休眠,开始执行
线程中断机制_第3张图片
在main方法中启动MyThread2线程,线程开始执行,遇到sleep方法然后阻塞10s,此时的main方法阻塞3s时间到,醒来调用interrupt()给MyThread2线程设置了请求中断标识(true),与此同时,MyThread2立马醒来,先将中断标识复位(false), 然后抛出一个中断异常InterruptedException 。这里要注意,在catch中需要对线程再发起一次中断请求,否则逻辑又进入修改状态,会无限循环下去。
当一个方法抛出 InterruptedException 时,它不仅告诉您它可以抛出一个特定的检查异常,而且还告诉您其他一些事情。例如,它告诉您它是一个阻塞(blocking)方法,如果您响应得当的话,它将尝试消除阻塞并尽早返回。
阻塞方法不同于一般的要运行较长时间的方法。一般方法的完成只取决于它所要做的事情,以及是否有足够多可用的计算资源(CPU 周期和内存)。而阻塞方法的完成还取决于一些外部的事件,例如计时器到期,I/O 完成,或者另一个线程的动作(释放一个锁,设置一个标志,或者将一个任务放在一个工作队列中)。一般方法在它们的工作做完后即可结束,而阻塞方法较难于预测,因为它们取决于外部事件。阻塞方法可能影响响应能力,因为难于预测它们何时会结束。
阻塞方法可能因为等不到所等的事件而无法终止,因此令阻塞方法可取消 就非常有用(如果长时间运行的非阻塞方法是可取消的,那么通常也非常有用)。可取消操作是指能从外部使之在正常完成之前终止的操作。由 Thread 提供并受 Thread.sleep() 和 Object.wait() 支持的中断机制就是一种取消机制;它允许一个线程请求另一个线程停止它正在做的事情。当一个方法抛出 InterruptedException 时,它是在告诉您,如果执行该方法的线程被中断,它将尝试停止它正在做的事情而提前返回,并通过抛出 InterruptedException 表明它提前返回。 行为良好的阻塞库方法应该能对中断作出响应并抛出 InterruptedException,以便能够用于可取消活动中,而不至于影响响应。

参考文献

1.关于线程中断的总结
2.你真的了解Java中的interrupt()中断线程吗?
3.Java并发之线程中断
4.Java精讲-线程中断

你可能感兴趣的:(多线程)