当前位置: 首页 > news >正文

设计模式之并发特定场景下的设计模式 Two-phase Termination(两阶段终止)模式

思考一下

  1. 在线程1中如何终止线程2?
  2. stop()?还是System.exit()?还是其他方式

方式解答

1.使用stop()不可取
线程对象的stop()方法会直接杀死线程,假设此时使用了线程锁,当此时使用了stop()命令会导致线程锁无法释放,以至于程序出现严重的问题,其中最常见的是死锁。还可能导致资源泄露,因为其他线程无法获取到被持有的资源。这可能会导致内存泄露或者其他资源的持续占用,最终导致系统资源耗尽。

什么是死锁?

死锁是指两个或多个线程相互持有对方所需的资源,导致它们都在等待对方释放资源,从而永远无法继续执行下去。当发生死锁时,程序可能会完全停止响应,或者表现出非常低的性能。在生产环境中,死锁可能导致程序崩溃或系统不稳定。

2.System.exit(int)不可取
System.exit(int)此方法是停止所有线程,此做法会使程序整个终止掉。

详细解释

  • 当调用System.exit(int) 时,JVM 将立即终止当前程序的执行,并返回一个整数状态码。通常情况下,返回值 0表示程序正常结束,非零值表示程序出现了某种异常或错误。这意味着可以根据System.exit(int) 返回值来判断程序的结束状态,并在必要时采取相应的措施。
  • 需要注意的是,调用System.exit(int)将立即终止程序的执行,因此任何在该方法调用之后的代码都将不会被执行。因此,需要小心使用该方法,避免在不必要的情况下过早地终止程序的执行。
  • 通常情况下,不建议在常规的程序流程中经常使用System.exit(int),除非在特定情况下需要强制结束程序的执行。更好的做法是通过返回值或异常来控制程序的执行流程。

正确停止: Two-phase Termination(两阶段终止)模式

  • 将终止过程分成两个阶段,其中第一个阶段主要是线程 T1 向线程 T2发送终止指令,而第 二阶段则是线程 T2响应终止指令。
  • Java 线程进入终止状态的前提是线程进入 RUNNABLE 状态,而利用java线程中断机制的interrupt()方法,可以让线程从休眠状态转换到RUNNABLE 状态。RUNNABLE 状态转换到终止状态,让 Java 线程自己执行完 run()方法,所以一般我们采用的方法是设置一个标志位,然后线程会在这个标志位检查,如果发现符合终止条件,则自动退出run() 方法。

两阶段终止模式是一种应用很广泛的并发设计模式,在 Java 语言中使用两阶段终止模式来终止线程,需要注意两个关键点:

  1. 仅检查终止标志位是不够的,因为线程的状态可能处于休眠态;
  2. 仅检查线程的中断状态也是不够的,因为我们依赖的第三方类库很可能没有正确处理中断异常.
    例如:
    Google Guava库中的com.google.common.io.Files类中的copy方法。在早期的版本中,这个方法可能没有正确处理中断异常。当在文件拷贝过程中线程被中断时,该方法可能会忽略中断并继续执行文件拷贝操作,而不会抛出InterruptedException。开发人员可能需要手动捕获中断异常并进行适当的处理。

使用场景

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

相关文章:

  • Linux中常使用的命令之ls、cd、pwd、mkdir、rmdir
  • 数字后端设计实现之自动化useful skew技术(Concurrent Clock Data)
  • Linux - No space left on device
  • 后端程序员开发win小工具(未完待续)
  • JS浏览器的默认行为及阻止行为,阻止右键菜单、阻止超链接跳转、阻止拖拽事件
  • k8s的yaml文件中的kind类型都有哪些?(详述版Part1/2)
  • C#高级 10 Linq操作
  • 记mongodb7.0安装时的常用操作 windows
  • Docker容器进入的4种方式(推荐最后一种)
  • 部署可道云网盘的一个漏洞解决
  • UISegmentedControl控件定制
  • 结构体的含义、表示、规范、运用
  • uniapp小程序当页面内容超出时显示滚动条,不超出时不显示---样式自定义
  • Python中魔术方法汇总
  • 华为OD机试 - 最小矩阵宽度(Java JS Python C)
  • __proto__ 和 prototype的关系
  • angular2 简述
  • DOM的那些事
  • ES6之路之模块详解
  • gulp 教程
  • Python_OOP
  • Redash本地开发环境搭建
  • 反思总结然后整装待发
  • 给第三方使用接口的 URL 签名实现
  • 排序(1):冒泡排序
  • 如何抓住下一波零售风口?看RPA玩转零售自动化
  • 时间复杂度与空间复杂度分析
  • 使用docker-compose进行多节点部署
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 微信支付JSAPI,实测!终极方案
  • 项目管理碎碎念系列之一:干系人管理
  • 译自由幺半群
  • 用jquery写贪吃蛇
  • 06-01 点餐小程序前台界面搭建
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • $.ajax()方法详解
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (1)bark-ml
  • (14)Hive调优——合并小文件
  • (23)Linux的软硬连接
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (WSI分类)WSI分类文献小综述 2024
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (第二周)效能测试
  • (转载)虚函数剖析
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .NET Core 项目指定SDK版本
  • .NET4.0并行计算技术基础(1)
  • .Net中间语言BeforeFieldInit
  • @Import注解详解
  • @PreAuthorize注解
  • [20171101]rman to destination.txt
  • [22]. 括号生成
  • [AIGC] Redis基础命令集详细介绍
  • [AutoSAR系列] 1.3 AutoSar 架构