首页
技术小册
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并发编程实战
### 09 | Java线程(上):Java线程的生命周期 在Java并发编程的广阔领域中,理解线程的生命周期是掌握多线程编程的基础。线程作为程序执行的基本单位,其从创建到销毁的整个过程构成了线程的生命周期。本章节将深入探讨Java线程的生命周期,包括其各个阶段、状态转换以及如何通过Java API管理和控制这些状态。 #### 一、线程生命周期概述 Java线程的生命周期主要可以分为以下几个阶段:新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、等待(Waiting)、超时等待(Timed Waiting)和终止(Terminated)。这些状态之间的转换,是线程在执行过程中根据系统调度和自身逻辑需要而发生的。 - **新建(New)**:线程被创建但尚未启动的状态。在这个阶段,线程对象已被创建,但线程调度系统还未将其纳入调度,因此它不会执行任何操作。 - **就绪(Runnable)**:线程已经准备好执行,但尚未被调度到CPU上执行。在就绪状态下,线程只是等待CPU的分配来执行其任务。 - **运行(Running)**:线程正在CPU上执行。这是线程生命周期中实际执行任务的阶段。 - **阻塞(Blocked)**:线程由于某种原因(如等待I/O操作完成或等待某个锁)暂时停止执行。阻塞状态结束后,线程会重新进入就绪状态。 - **等待(Waiting)**:线程在等待某个条件成立而进入的状态。这个状态是无限期等待的,直到其他线程显式地唤醒它。 - **超时等待(Timed Waiting)**:与等待状态类似,但超时等待状态会在指定的时间后自动返回,即使条件未满足。 - **终止(Terminated)**:线程执行完毕或被中断后结束的状态。这是线程生命周期的终点。 #### 二、线程状态的转换 Java线程的状态转换是线程调度的核心。以下是一些常见的状态转换路径及其触发条件: 1. **新建(New) -> 就绪(Runnable)**:当调用线程的`start()`方法时,线程由新建状态进入就绪状态。注意,直接调用`run()`方法并不会启动线程,而只是在当前线程中同步执行`run()`方法内的代码。 2. **就绪(Runnable)-> 运行(Running)**:当线程调度器选中一个就绪状态的线程时,该线程进入运行状态。这个转换是由操作系统的线程调度器自动完成的,Java程序无法直接控制。 3. **运行(Running)-> 阻塞(Blocked)**:线程在运行过程中,可能因为等待某个资源(如IO操作、锁等)而进入阻塞状态。一旦资源可用或锁被释放,线程将返回到就绪状态。 4. **运行(Running)/ 阻塞(Blocked)-> 等待(Waiting)**:线程可以通过调用`Object`类的`wait()`方法或`Thread`类的`join()`方法等方法进入等待状态。这些操作通常涉及线程间的同步和通信。 5. **等待(Waiting)/ 阻塞(Blocked)-> 超时等待(Timed Waiting)**:线程可以通过调用带超时参数的`wait(long timeout)`、`sleep(long millis)`或`join(long millis)`等方法进入超时等待状态。这些操作允许线程在指定的时间后自动返回,即使等待的条件未满足。 6. **超时等待(Timed Waiting)/ 等待(Waiting)/ 阻塞(Blocked)-> 就绪(Runnable)**:当超时时间到达、等待条件满足或阻塞原因消除时,线程将返回到就绪状态,等待CPU的调度。 7. **运行(Running)/ 就绪(Runnable)-> 终止(Terminated)**:线程执行完毕或调用`stop()`方法(但`stop()`方法已被废弃,不推荐使用)时,线程进入终止状态。从Java 1.2开始,推荐使用`interrupt()`方法来中断线程,线程应在自己的代码中响应中断并优雅地结束。 #### 三、Java API对线程状态的支持 Java API提供了丰富的类和方法来管理和控制线程的状态。以下是一些关键的类和方法: - **Thread类**:Java中所有线程都是`Thread`类或其子类的实例。`Thread`类提供了启动线程(`start()`)、停止线程(通过中断机制)、获取线程状态(`getState()`)、等待(`join()`)、睡眠(`sleep()`)等方法。 - **Object类**:`Object`类中的`wait()`、`notify()`和`notifyAll()`方法是Java线程间通信的基础。这些方法必须在同步代码块或同步方法中调用,因为它们依赖于对象的监视器锁。 - **Lock接口及其实现**:从Java 1.5开始,`java.util.concurrent.locks`包提供了比`synchronized`关键字更灵活的锁机制。`Lock`接口及其实现(如`ReentrantLock`)提供了尝试锁定(`tryLock()`)、可中断地锁定(`lockInterruptibly()`)、定时锁定(`tryLock(long time, TimeUnit unit)`)等功能,这些功能为线程的状态控制提供了更多的灵活性和控制力。 #### 四、最佳实践与注意事项 1. **避免直接调用`run()`方法**:直接调用线程的`run()`方法会在当前线程中同步执行`run()`方法内的代码,而不是启动新线程。要启动新线程,应调用`start()`方法。 2. **合理使用中断机制**:`interrupt()`方法是线程间协作的中断机制,它比`stop()`方法更安全、更优雅。线程应在其`run()`方法内部定期检查中断状态,并据此做出相应的处理。 3. **注意线程间的同步与通信**:使用`wait()`、`notify()`和`notifyAll()`等方法时,必须确保它们被调用在持有适当锁的对象的同步代码块或同步方法中。同时,应避免在持有锁时执行耗时的操作,以免导致死锁或降低系统性能。 4. **利用并发工具类**:Java并发包(`java.util.concurrent`)提供了丰富的并发工具类,如`ExecutorService`、`CountDownLatch`、`CyclicBarrier`、`Semaphore`等,这些工具类能够大大简化并发编程的复杂度,并提高程序的性能和可靠性。 #### 五、总结 Java线程的生命周期是Java并发编程中的一个核心概念。通过深入理解线程的各个状态及其转换机制,我们可以更加有效地管理和控制线程的执行。同时,借助Java API提供的丰富工具和方法,我们可以编写出更加高效、稳定、可维护的并发程序。在实际编程过程中,我们应遵循最佳实践,合理使用中断机制、同步与通信工具,以及并发工具类,以提高程序的性能和可靠性。
上一篇:
08 | 管程:并发编程的万能钥匙
下一篇:
10 | Java线程(中):创建多少线程才是合适的?
该分类下的相关小册推荐:
深入理解Java虚拟机
Java语言基础2-运算符
Java语言基础10-Java中的集合
Java必知必会-Maven初级
Java语言基础13-类的加载和反射
Java语言基础7-Java中的异常
Java语言基础14-枚举和注解
Java必知必会-Maven高级
Java必知必会-JDBC
Java语言基础4-数组详解
Java语言基础12-网络编程
Java高并发秒杀入门与实战