【并发设计模式】聊聊两阶段终止模式如何优雅终止线程

news/2024/7/23 16:25:36 标签: 设计模式, java, 开发语言

在软件设计中,抽象出了23种设计模式,用以解决对象的创建、组合、使用三种场景。在并发编程中,针对线程的操作,也抽象出对应的并发设计模式

  • 两阶段终止模式- 优雅停止线程
  • 避免共享的设计模式- 只读、Copy-on-write、Thread-Specific Storage
  • 多线程版本的if模式
  • 多线程分工模式 (Thread-per-Message 、Worker Thread、生产者-消费者模式)

从今天开始我们会开始逐篇讲解这几种并发设计模式

最简单的方式其实就是调用线程的Stop方法,但是这个方法不推荐使用,原因是会直接将线程杀死。对于业务是不允许的。太粗暴了。

两阶段终止模式

两阶段终止模式其实就是将线程终止的过程分成两个过程。
第一个过程T1向线程T2发送终止指令,第二个过程T2响应终止指令。
在这里插入图片描述
但是本身线程想进入终止状态,那么必然要从运行状态转换,但是这个线程可能是休眠状态,block、wait、time_wait 三种状态。所以需要使用Thread类的interrupt()方法 将线程从休眠状态转换到runnable状态。然后我们设置一个中断位,T2线程检查到需要终止就会直接停止。

一个案例

java">public class Proxy {

    private boolean isStart = false;
    // 对于stop的方法的修改 需要被start()方法 获取到,变量的可见性 
    private volatile boolean termial = false;
    private Thread runTask;

    synchronized void start () {

        runTask = new Thread(() -> {
            if (isStart) {
                return;
            }

            isStart = true;

            while (!Thread.currentThread().isInterrupted() || !termial) {
                try {
                    System.out.println("send->监控数据>监控平台");
                    TimeUnit.SECONDS.sleep(2);
                } catch (Exception e) {
                    Thread.currentThread().interrupt();
                    e.printStackTrace();
                }
            }

            isStart = false;
            System.out.println(Thread.currentThread().getName() + " stop");
        });

        runTask.start();
    }

    synchronized void stop () {
        runTask.interrupt();
        termial = true;
    }

}

终止线程池

对于终止线程池,shutdown()和shutdownNow() 前者其实会将线程池在处理以及阻塞队列中的任务处理完毕,后者会直接拒绝执行任何任务, shutdownNow的返回值是等得队列中未被执行的任务。所以在实际的使用中不推荐直接使用这两个方法。更优的方法其实是

java">		pool.shutdown();
        boolean terminated = false;
        while (!terminated) {
            pool.awaitTermination(100,TimeUnit.SECONDS);
        }

两阶段终止模式是一种应用很广泛的并发设计模式,在 Java 语言中使用两阶段终止模式来 优雅地终止线程,需要注意两个关键点: 一个是仅检查终止标志位是不够的,因为线程的状态 可能处于休眠态;另一个是仅检查线程的中断状态也是不够的,因为我们依赖的第三方类库很 可能没有正确处理中断异常, 例如第三方类库在捕获到 Thread.sleep() 方法抛出的中断异常 后,没有重新设置线程的中断状态,那么就会导致线程不能够正常终止。所以我们可以自定义 线程的终止标志位用于终止线程。

小结

好了本篇主要介绍到这里。其实两阶段终止模式主要用以在终止线程的时候,

使用场景

  1. 安全地终止线程,比如释放该释放的资源;
  2. 要确保终止处理逻辑在线程结束之前一定会执行时,可使用该方法;

http://www.niftyadmin.cn/n/5283495.html

相关文章

Qml之自定义Button

Qml之自定义Button 前言一、图标Button二、字体Button1.重写Background和ContentItem2.采用ButtonStyle 前言 提示: 自定义Button控件如何分为带图片的Iconbutton和原生控件重写的Button。最终效果如下: 提示:以下是本篇文章正文内容&#x…

log4j rename方法

log4j日志切割 os.rename [rootzz test]# cat a2.py import os os.rename(a.txt,b.txt); [rootzz test]# cat a.txt 111111111111111111111 222222222222222222222 [rootzz test]# ls a1.py a2.py a.txt tst.log.1 tst.log.2 [rootzz test]# python ^C [rootzz test]# s…

Java 8中流Stream API详解

先给个示例,展示Java 8流API的优势 假设我们有以下任务: 给定一个字符串列表,我们需要执行以下操作: 筛选出所有以"A"开头的字符串。 将这些字符串转换为大写。 对这些字符串按照长度进行排序。 最后,将…

Pytorch 读取t7文件

Pytorch 1.0以上可以使用: import torchfileth_path r"./path/xx.t7" data torchfile.load(th_path)print(data.shape)若data的尺寸为0,则将torch版本降为0.4.1,并使用以下函数: from torch.utils.serialization im…

PostgreSQL数据类型及基本操作

文章目录 一、数据类型二、对比MySQL三、基本操作1、单引号和双引号2、数据类型转换3、数字类型1)整数2)浮点数3)序列4)常见操作 4、 字符串类型5、 日期类型1)声明时间2)日期类型的运算 6、 布尔类型7、 枚…

swing快速入门(二十六)五子棋

注释很详细,直接上代码 上一篇 新增内容 1. 界面闪烁问题处理方法 2. 取整定点动态确定下子点 3.鼠标移动事件实现动态选择框 4.鼠标点击事件与离开事件响应方法 package swing21_30;import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*;…

【Android 13】使用Android Studio调试系统应用之Settings移植(一):编译服务器的配置、AOSP源码的下载、编译、运行

文章目录 1. 篇头语2. 系列文章3. ubuntu 最佳版本3.1 下载并安装3.2 配置AOSP工具链3.3 配置Python多版本支持4. AOSP源码下载4.1 配置repo工具4.2 源码下载5. AOSP编译5.1 添加emulator模拟器配置5.1.1 哪些是支持模拟器的Products?5.1.2 添加方法5.2 编译

c语言中一维数组在计算机内部的二进制数存储规则

在C语言中,一维数组变量的存储和二进制表示是按照数组元素的顺序连续存储的。每个数组元素占用相同的内存空间,根据其数据类型的大小来确定。例如,如果定义了一个整型数组,数组名为a,定义的数组称为数组a。 对于字符型…