一, 线程中断
1. 什么是线程中断?
线程中断是线程的标志位属性. 而不是真正终止线程, 和线程的状态无关. 线程中断过程表示一个运行中的线程, 通过其他线程调用了该线程的 interrupt() 方法, 使得该线程中断标志位属性改变.
深入思考下, 线程中断不是去中断了线程, 恰恰是用来通知该线程应该被中断了. 具体是一个标志位属性, 到底该线程生命周期是去终止, 还是继续运行, 由线程根据标志位属性自行处理.
2. 线程中断操作
调用线程的 interrupt() 方法, 根据线程不同的状态会有不同的结果.
下面新建 InterruptedThread 对象, 代码如下:
- /**
- * 一直运行的线程, 中断状态为 true
- *
- * @author Jeff Lee @ bysocket.com
- * @since 2018 年 02 月 23 日 19:03:02
- */
- public class InterruptedThread implements Runnable {
- @Override // 可以省略
- public void run() {
- // 一直 run
- while (true) {
- }
- }
- public static void main(String[] args) throws Exception {
- Thread interruptedThread = new Thread(new InterruptedThread(), "InterruptedThread");
- interruptedThread.start();
- TimeUnit.SECONDS.sleep(2);
- interruptedThread.interrupt();
- System.out.println("InterruptedThread interrupted is" + interruptedThread.isInterrupted());
- TimeUnit.SECONDS.sleep(2);
- }
- }
运行 main 函数, 结果如下:
InterruptedThread interrupted is true
代码详解:
线程一直在运行状态, 没有停止或者阻塞等
调用了 interrupt() 方法, 中断状态置为 true, 但不会影响线程的继续运行
另一种情况, 新建 InterruptedException 对象, 代码如下:
- /**
- * 抛出 InterruptedException 的线程, 中断状态被重置为默认状态 false
- *
- * @author Jeff Lee @ bysocket.com
- * @since 2018 年 02 月 23 日 19:03:02
- */
- public class InterruptedException implements Runnable {
- @Override // 可以省略
- public void run() {
- // 一直 sleep
- try {
- TimeUnit.SECONDS.sleep(10);
- } catch (java.lang.InterruptedException e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) throws Exception {
- Thread interruptedThread = new Thread(new InterruptedException(), "InterruptedThread");
- interruptedThread.start();
- TimeUnit.SECONDS.sleep(2);
- // 中断被阻塞状态 (sleep,wait,join 等状态) 的线程, 会抛出异常 InterruptedException
- // 在抛出异常 InterruptedException 前, JVM 会先将中断状态重置为默认状态 false
- interruptedThread.interrupt();
- System.out.println("InterruptedThread interrupted is" + interruptedThread.isInterrupted());
- TimeUnit.SECONDS.sleep(2);
- }
- }
运行 main 函数, 结果如下:
- InterruptedThread interrupted is false
- java.lang.InterruptedException: sleep interrupted
- at java.lang.Thread.sleep(Native Method)
代码详解:
中断被阻塞状态 (sleep,wait,join 等状态) 的线程, 会抛出异常 InterruptedException
抛出异常 InterruptedException 前, JVM 会先将中断状态重置为默认状态 false
小结下线程中断:
线程中断, 不是停止线程, 只是一个线程的标志位属性
如果线程状态为被阻塞状态(sleep,wait,join 等状态), 线程状态退出被阻塞状态, 抛出异常 InterruptedException, 并重置中断状态为默认状态 false
如果线程状态为运行状态, 线程状态不变, 继续运行, 中断状态置为 true
代码: https://github.com/JeffLi1993/java-concurrency-core-learning
二. 线程终止
比如在 IDEA 中强制关闭程序, 立即停止程序, 不给程序释放资源等操作, 肯定是不正确的. 线程终止也存在类似的问题, 所以需要考虑如何终止线程?
上面聊到了线程中断, 可以利用线程中断标志位属性来安全终止线程. 同理也可以使用 boolean 变量来控制是否需要终止线程.
新建 , 代码如下:
- /**
- * 安全终止线程
- *
- * @author Jeff Lee @ bysocket.com
- * @since 2018 年 02 月 23 日 19:03:02
- */
- public class ThreadSafeStop {
- public static void main(String[] args) throws Exception {
- Runner one = new Runner();
- Thread countThread = new Thread(one, "CountThread");
- countThread.start();
- // 睡眠 1 秒, 通知 CountThread 中断, 并终止线程
- TimeUnit.SECONDS.sleep(1);
- countThread.interrupt();
- Runner two = new Runner();
- countThread = new Thread(two,"CountThread");
- countThread.start();
- // 睡眠 1 秒, 然后设置线程停止状态, 并终止线程
- TimeUnit.SECONDS.sleep(1);
- two.stopSafely();
- }
- private static class Runner implements Runnable {
- private long i;
- // 终止状态
- private volatile boolean on = true;
- @Override
- public void run() {
- while (on && !Thread.currentThread().isInterrupted()) {
- // 线程执行具体逻辑
- i++;
- }
- System.out.println("Count i =" + i);
- }
- public void stopSafely() {
- on = false;
- }
- }
- }
从上面代码可以看出, 通过 while (on && !Thread.currentThread().isInterrupted()) 代码来实现线程是否跳出执行逻辑, 并终止. 但是疑问点就来了, 为啥需要 on 和 isInterrupted() 两项一起呢? 用其中一个方式不就行了吗? 答案在下面
线程成员变量 on 通过 volatile 关键字修饰, 达到线程之间可见, 从而实现线程的终止. 但当线程状态为被阻塞状态 (sleep,wait,join 等状态) 时, 对成员变量操作也阻塞, 进而无法执行安全终止线程
为了处理上面的问题, 引入了 isInterrupted(); 只去解决阻塞状态下的线程安全终止.
两者结合是真的没问题了吗? 不是的, 如果是网络 io 阻塞, 比如一个 websocket 一直再等待响应, 那么直接使用底层的 close .
三, 小结
很多好友介绍, 如果用 Spring 栈开发到使用线程或者线程池, 那么尽量使用框架这块提供的线程操作及框架提供的终止等
来源: http://www.jianshu.com/p/0b43992d6f93