• 并发编程学习笔记(三、如何安全地终止线程)


    目录:

    • 设置退出标识
    • interrupt()方法
    • 废弃的终止方式
    • 总结

    设置退出标识:

     1 public class FlagThread extends Thread {
     2     /**
     3      * 退出标识
     4      */
     5     public volatile boolean exit = false;
     6 
     7     @Override
     8     public void run() {
     9         while (!exit) {
    10         }
    11         System.out.println("ThreadFlag线程退出");
    12     }
    13 
    14     public static void main(String[] args) throws Exception {
    15         FlagThread threadFlag = new FlagThread();
    16         threadFlag.start();
    17         // 主线程延迟3秒
    18         sleep(3000);
    19         // todo 终止线程thread
    20         threadFlag.exit = true;
    21         // main线程放弃cpu使用权
    22         // 让threadFlag线程继续执行,直到threadFlag运行完
    23         threadFlag.join();
    24         System.out.println("线程退出!");
    25     }
    26 }

    通过第5行的exit属性来表示线程是否应该退出;但这种方法有一个弊端,若线程阻塞时标识便不起作用了。

    在定义exit时,使用了一个Java关键字volatile,这个关键字的目的是保证exit内存可见性,也就是对exit的修改会立刻对其他线程可见

    interrupt()方法:

     1 public class InterruptThread extends Thread {
     2     /**
     3      * 退出标识
     4      */
     5     volatile boolean exit = false;
     6 
     7     @Override
     8     public void run() {
     9         while (!exit) {
    10             System.out.println(getName() + " is running");
    11             try {
    12                 Thread.currentThread().join();
    13             } catch (InterruptedException e) {
    14                 System.out.println("week up from block...");
    15                 // 在异常处理代码中修改共享变量的状态
    16                 exit = true;
    17             }
    18         }
    19         System.out.println(getName() + " is exiting...");
    20     }
    21 
    22     public static void main(String[] args) throws InterruptedException {
    23         InterruptThread interruptThread = new InterruptThread();
    24         System.out.println("Starting thread...");
    25         interruptThread.start();
    26         Thread.sleep(3000);
    27         System.out.println("Interrupt thread...: " + interruptThread.getName());
    28         // 设置退出标识为true
    29         interruptThread.exit = true;
    30         interruptThread.interrupt();
    31         // 主线程休眠3秒以便观察线程interruptThread的中断情况
    32         Thread.sleep(3000);
    33         System.out.println("Stopping application...");
    34     }
    35 }

    若第30行注释,则在执行到第25行,运行到第12行时,线程一直在等待自己执行完,所以线程阻塞了,导致29行的标识无用。

    此种情况只需要主动的中断线程即可(第30行代码)。

    废弃的终止方式

    1、Thread.stop:

    • Thread.stop()来强行终止线程,但是stop方法是很危险的,就像突然拔掉计算机电源,而不是按正常程序关机一样,可能会产生不可预料的结果。
    • Thread.stop()调用之后,创建子线程的线程就会抛出ThreadDeath这个Error强行释放子线程持有的锁,导致被保护的资源出现线程安全问题

    2、Thread.suspend / Thread.resume:

    • Thread.suspend
      • 使线程暂停。
      • 不会释放类似锁这样的资源。
    • Thread.resume
      • 使线程恢复。
      • 如果之前没有使用suspend暂停线程,则不起作用
      • suspend()和resume()必须要成对出现,否则非常容易发生死锁。因为suspend方法并不会释放锁,如果使用suspend的目标线程对一个重要的系统资源持有锁,那么没任何线程可以使用这个资源,直到要suspend的目标线程被resumed,如果一个线程在resume目标线程之前尝试持有这个重要的系统资源锁再去resume目标线程,这两条线程就相互死锁了。

    3、Runtime.runFinalizersOnExit:

    • 这个方法本身就是不安全的。
    • 它可能导致终结器(finalizers)被在活跃对象上被调用,而其他线程正在并发操作这些对象。而且,这个调用不是“线程安全”的,因为它设置了一个VM全局标志。
  • 相关阅读:
    echart自定义浮窗 增加点击事件
    原生js学习 选择dom
    GOjs版本2.0去除水印
    js 作用域
    javaScript的原型模式
    JavaScript的基本包装类型说明
    原生js 函数 callee属性
    Vue学习-基本指令
    js函数
    Kubernetes(一):云计算发展历程
  • 原文地址:https://www.cnblogs.com/bzfsdr/p/11565280.html
Copyright © 2020-2023  润新知