首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
01 | 可见性、原子性和有序性问题:并发编程Bug的源头
02 | Java内存模型:看Java如何解决可见性和有序性问题
03 | 互斥锁(上):解决原子性问题
04 | 互斥锁(下):如何用一把锁保护多个资源?
05 | 一不小心就死锁了,怎么办?
06 | 用“等待-通知”机制优化循环等待
07 | 安全性、活跃性以及性能问题
08 | 管程:并发编程的万能钥匙
09 | Java线程(上):Java线程的生命周期
10 | Java线程(中):创建多少线程才是合适的?
11 | Java线程(下):为什么局部变量是线程安全的?
12 | 如何用面向对象思想写好并发程序?
13 | 理论基础模块热点问题答疑
14 | Lock和Condition(上):隐藏在并发包中的管程
15 | Lock和Condition(下):Dubbo如何用管程实现异步转同步?
16 | Semaphore:如何快速实现一个限流器?
17 | ReadWriteLock:如何快速实现一个完备的缓存?
18 | StampedLock:有没有比读写锁更快的锁?
19 | CountDownLatch和CyclicBarrier:如何让多线程步调一致?
20 | 并发容器:都有哪些“坑”需要我们填?
21 | 原子类:无锁工具类的典范
22 | Executor与线程池:如何创建正确的线程池?
23 | Future:如何用多线程实现最优的“烧水泡茶”程序?
24 | CompletableFuture:异步编程没那么难
25 | CompletionService:如何批量执行异步任务?
26 | Fork/Join:单机版的MapReduce
27 | 并发工具类模块热点问题答疑
28 | Immutability模式:如何利用不变性解决并发问题?
29 | Copy-on-Write模式:不是延时策略的COW
30 | 线程本地存储模式:没有共享,就没有伤害
31 | Guarded Suspension模式:等待唤醒机制的规范实现
32 | Balking模式:再谈线程安全的单例模式
33 | Thread-Per-Message模式:最简单实用的分工方法
34 | Worker Thread模式:如何避免重复创建线程?
35 | 两阶段终止模式:如何优雅地终止线程?
36 | 生产者-消费者模式:用流水线思想提高效率
37 | 设计模式模块热点问题答疑
38 | 案例分析(一):高性能限流器Guava RateLimiter
39 | 案例分析(二):高性能网络应用框架Netty
40 | 案例分析(三):高性能队列Disruptor
41 | 案例分析(四):高性能数据库连接池HiKariCP
42 | Actor模型:面向对象原生的并发模型
43 | 软件事务内存:借鉴数据库的并发经验
44 | 协程:更轻量级的线程
45 | CSP模型:Golang的主力队员
当前位置:
首页>>
技术小册>>
Java并发编程实战
小册名称:Java并发编程实战
### 章节 35 | 两阶段终止模式:如何优雅地终止线程? 在Java并发编程的广阔领域中,线程的优雅终止是一个至关重要但又常被忽视的话题。线程作为程序执行的基本单位,其生命周期的管理直接关系到程序的稳定性、响应性和资源利用率。不恰当的线程终止方式可能会导致数据不一致、资源泄露或死锁等问题。因此,掌握一种或多种线程优雅终止的模式对于编写健壮的并发程序至关重要。本章将深入探讨“两阶段终止模式”,一种广泛认可的优雅终止线程的方法。 #### 35.1 引言 在多线程环境中,线程的终止通常不是由线程自身控制完成的,而是由外部因素触发,如用户请求、系统资源限制或程序逻辑的需要。直接调用线程的`stop()`方法是不被推荐的,因为它会立即停止线程,且不会释放线程所占用的资源,同时会抛出`ThreadDeath`异常,这可能导致程序逻辑错误或资源状态不一致。因此,我们需要一种更加温和、可控的方式来终止线程,这就是两阶段终止模式的用武之地。 #### 35.2 两阶段终止模式概述 两阶段终止模式(Two-Phase Termination Pattern)是一种设计模式,用于优雅地终止线程。该模式将线程的终止过程分为两个阶段:请求终止阶段和真正终止阶段。通过这两个阶段,线程可以安全地释放资源、完成当前任务,并最终退出。 ##### 第一阶段:请求终止 在第一阶段,线程外部通过某种机制(如设置标志位、发送中断信号等)向线程发出终止请求。线程在检测到终止请求后,会开始准备终止工作,但这并不意味着立即停止执行。相反,它会继续完成当前任务或将其置于安全状态,以便在后续阶段进行清理。 ##### 第二阶段:真正终止 在第二阶段,线程在确保所有待处理任务都已安全处理后,开始释放所占用的资源(如锁、文件句柄等),并最终退出执行。这一阶段可能需要一些时间来完成,具体取决于线程当前的状态和任务性质。 #### 35.3 实现两阶段终止模式的步骤 实现两阶段终止模式通常涉及以下几个步骤: 1. **定义终止标志**: 在线程类中定义一个标志位(如布尔变量`isRunning`),用于指示线程是否应该继续运行。线程在循环执行任务时,应定期检查此标志位。 2. **提供请求终止的方法**: 提供一个公共方法(如`requestTermination()`),允许外部调用者设置终止标志位,请求线程终止。 3. **检查终止请求**: 在线程的执行循环中,定期检查终止标志位。如果检测到终止请求,则开始执行终止前的清理工作,如停止接收新任务、完成当前任务等。 4. **中断敏感的任务处理**: 对于可能长时间运行的任务,应考虑使它们对中断敏感。即,在任务执行过程中定期检查线程的中断状态(通过`Thread.currentThread().isInterrupted()`),并在检测到中断时进行相应的处理。 5. **资源释放与退出**: 在确保所有任务都已完成或安全处理后,线程应释放其占用的所有资源,并退出执行循环。可以通过`return`语句、循环条件变更或抛出特定异常(如`InterruptedException`)来实现。 6. **异常处理**: 在任务执行过程中,应妥善处理可能出现的异常,确保即使在异常情况下也能正确释放资源并安全退出。 #### 35.4 示例代码 下面是一个简单的示例,展示了如何在Java中实现两阶段终止模式: ```java public class GracefulTerminationThread extends Thread { private volatile boolean isRunning = true; @Override public void run() { try { while (isRunning || !Thread.currentThread().isInterrupted()) { // 执行任务,这里用简单的打印代替 System.out.println("Executing task..."); // 模拟任务执行时间 Thread.sleep(1000); // 检查是否有中断请求 if (Thread.currentThread().isInterrupted()) { System.out.println("Thread interruption detected. Preparing to exit..."); // 处理中断前的清理工作(如果有) // 清除中断状态,因为后续操作不再需要 Thread.interrupted(); // 退出循环 break; } // 检查是否收到终止请求 if (!isRunning) { System.out.println("Termination requested. Finishing current task..."); // 完成当前任务或进行其他清理工作 // 退出循环 break; } } // 释放资源(如果有) System.out.println("Thread exiting gracefully."); } catch (InterruptedException e) { // 处理中断异常 Thread.currentThread().interrupt(); // 可选:重新设置中断状态 System.out.println("Thread interrupted and exiting."); } } // 请求终止线程 public void requestTermination() { isRunning = false; } } // 使用示例 public class Main { public static void main(String[] args) throws InterruptedException { GracefulTerminationThread thread = new GracefulTerminationThread(); thread.start(); // 假设一段时间后请求终止线程 Thread.sleep(5000); thread.requestTermination(); // 等待线程真正终止 thread.join(); } } ``` #### 35.5 注意事项 - **线程安全性**:确保终止标志位(如`isRunning`)是`volatile`的,以避免多线程环境下的可见性问题。 - **中断处理**:合理利用Java的中断机制,使任务对中断敏感,以便在必要时能够迅速响应终止请求。 - **资源清理**:确保在终止过程中释放所有占用的资源,避免资源泄露。 - **异常管理**:妥善处理可能出现的异常,确保线程在异常情况下也能安全退出。 - **避免死锁**:在终止过程中,避免创建新的锁依赖关系,以防止死锁的发生。 #### 35.6 结论 两阶段终止模式是一种优雅且有效的线程终止方法,它通过明确的终止请求和逐步的资源释放,确保了线程在终止过程中的稳定性和安全性。掌握这一模式,对于编写高质量的Java并发程序具有重要意义。在实际应用中,我们可以根据具体需求,灵活调整终止逻辑和资源释放策略,以达到最佳效果。
上一篇:
34 | Worker Thread模式:如何避免重复创建线程?
下一篇:
36 | 生产者-消费者模式:用流水线思想提高效率
该分类下的相关小册推荐:
Java语言基础3-流程控制
SpringBoot合辑-初级篇
Mybatis合辑4-Mybatis缓存机制
Java语言基础13-类的加载和反射
Java语言基础4-数组详解
Java必知必会-JDBC
深入理解Java虚拟机
Mybatis合辑5-注解、扩展、SQL构建
Java语言基础7-Java中的异常
Java性能调优实战
SpringBoot零基础到实战
Java必知必会-Maven初级