zoukankan      html  css  js  c++  java
  • 泥瓦匠聊并发编程基础篇:线程中断和终止

    1 线程中断

    1.1 什么是线程中断?

    线程中断是线程的标志位属性。而不是真正终止线程,和线程的状态无关。线程中断过程表示一个运行中的线程,通过其他线程调用了该线程的 interrupt() 方法,使得该线程中断标志位属性改变。

    深入思考下,线程中断不是去中断了线程,恰恰是用来通知该线程应该被中断了。具体是一个标志位属性,到底该线程生命周期是去终止,还是继续运行,由线程根据标志位属性自行处理。

    1.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

    2 线程终止

    比如在 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()) 代码来实现线程是否跳出执行逻辑,并终止。但是疑问点就来了,为啥需要 onisInterrupted() 两项一起呢?用其中一个方式不就行了吗?答案在下面

    • 线程成员变量 on 通过 volatile 关键字修饰,达到线程之间可见,从而实现线程的终止。但当线程状态为被阻塞状态(sleep、wait、join 等状态)时,对成员变量操作也阻塞,进而无法执行安全终止线程
    • 为了处理上面的问题,引入了 isInterrupted(); 只去解决阻塞状态下的线程安全终止。
    • 两者结合是真的没问题了吗?不是的,如果是网络 io 阻塞,比如一个 websocket 一直再等待响应,那么直接使用底层的 close 。

    3 小结

    很多好友介绍,如果用 Spring 栈开发到使用线程或者线程池,那么尽量使用框架这块提供的线程操作及框架提供的终止等

    资料:
    《Java 并发编程的艺术》

  • 相关阅读:
    git 命令速查及使用
    Centos6.5 LAMP环境源码包安装与配置,附安装包百度网盘地址 (转做笔记)
    不再为Apache进程淤积、耗尽内存而困扰((转))
    centos6.5 安装linux 环境
    window 配置wnmp(转下整理 ,全)
    mac下安装 xampp 无法启动apache (转,留用)
    Git命令行(转用于学习和记录)
    apache 局域网访问
    华为云GaussDB(for opengauss)如何绑定公网,实现putty的远程访问gaussdb数据库。
    Day9 打卡acwing.429 奖学金
  • 原文地址:https://www.cnblogs.com/Alandre/p/8507505.html
Copyright © 2011-2022 走看看