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

发布时间:2024年01月11日

思考一下

  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. 要确保终止处理逻辑在线程结束之前一定会执行时,可使用该方法;
文章来源:https://blog.csdn.net/weixin_44859605/article/details/135527877
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。