李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
08.并发编程之线程状态
Leefs
2022-10-09 PM
1005℃
0条
[TOC] ### 一、五种状态 五种状态的划分主要是从操作系统的层面进行划分的 ![08.并发编程之线程状态01.png](https://lilinchao.com/usr/uploads/2022/10/129890244.png) **1. 新建状态(New):** 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。 **2. 就绪状态(Runnable):** 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,`thread.start()`。处于就绪状态的线程,随时可能被CPU调度执行。 **3. 运行状态(Running):** 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。 **4. 阻塞状态(Blocked):** 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种: - **等待阻塞**:通过调用线程的wait()方法,让线程等待某工作的完成。 - **同步阻塞**:线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。 - **其他阻塞**:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。 **5. 死亡状态(Dead):** 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。 ### 二、六种状态 这是从 **Java API** 层面来描述的 根据 `Thread.State` 枚举,分为六种状态 ```java public enum State { // 新建状态 NEW, // 运行状态 RUNNABLE, /** * 阻塞状态 * Object.wait */ BLOCKED, /** * 等待状态 * Object.wait * Thread.join * LockSupport.park */ WAITING, /** * 限时等待状态 * Thread.sleep * Object.wait * Thread.join * LockSupport.parkUntil * LockSupport.parkNanos */ TIMED_WAITING, // 终止状态 TERMINATED; } ``` + **NEW(新建状态)**:创建后,启动前。线程就处于该状态。 + **RUNNABLE(可运行状态)**:线程正在执行代码,就处于该状态。 + **BLOCKED(阻塞状态)**:一个线程获取synchronized锁对象失败,就处于该状态。 + **WAITING(无限等待)**:一个线程获取Lock锁对象失败,就处于该状态。调用wait方法,线程也处于该状态。 + **TIMED_WAITING(计时等待状态)**:线程正在执行sleep方法,就处于该状态。 + **TERMINATED(消亡状态)**:线程把任务执行完毕后,就处于该状态。 #### 说明 ![08.并发编程之线程状态02.png](https://lilinchao.com/usr/uploads/2022/10/2057451094.png) + NEW 跟五种状态里的初始状态是一个意思 + RUNNABLE 是当调用了 start() 方法之后的状态,注意,Java API 层面的 RUNNABLE 状态涵盖了操作系统层面的【可运行状态】、【运行状态】和【io阻塞状态】(由于 BIO 导致的线程阻塞,在 Java 里无法区分,仍然认为是可运行) + BLOCKED , WAITING , TIMED_WAITING 都是 Java API 层面对【阻塞状态】的细分。 #### 详解 假设有线程 Thread t ##### 情况1:NEW–>RUNNABLE 当调用t.start()方法时,由 NEW --> RUNNABLE ##### 情况2:RUNNABLE <–> WAITING t线程用synchronized(obj)获取了对象锁后 + 调用obj.wait() 方法时,t线程从RUNNABLE --> WAITING + 调用obj.notify(),obj.notifyAll(), t.interrupt()时 + 竞争锁成功,t线程从WAITING --> RUNNABLE + 竞争锁失败,t线程从WAITING --> BLOCKED ##### 情况3:RUNNABLE <–> WAITING + 当前线程调用 t.join()方法时,当前线程从 RUNNABLE --> WAITING + 注意是当前线程在 t线程对象的监视器上等待 + t线程运行结束,或调用了当前线程的interrupt()时,当前线程从WAITING -->RUNNABLE ##### 情况4:RUNNABLE <–> WAITING + 当前线程调用 `LockSupport.park()` 会让当前线程从 RUNNABLE --> WAITING + 调用 `LockSupport.unpark(目标线程)`或调用了线程的 interrupt(),会让目标线程从 `WAITING -->RUNNABLE` ##### 情况5:RUNNABLE <–> TIMED_WAITING + t线程用`synchronized(obj)`获取了对象锁后 + 调用 `obj.wait(long n)`方法时,t线程从 RUNNABLE --> TIMED_WAITING + t线程等待时间超过了n毫秒,或调用obj.notify(),obj.notifyAll(), t.interrupt()时 + 竞争锁成功,t线程从`TIMED_WAITING--> RUNNABLE` + 竞争锁失败,t线程从`TIMED_WAITING--> BLOCKED` ##### 情况6:RUNNABLE <–> TIMED_WAITING + 当前线程调用 `t.join(long n)`方法时,当前线程从 RUNNABLE --> TIMED_WAITING + 注意是当前线程在t线程对象的监视器上等待 + 当前线程等待时间超过了n毫秒,或t线程运行结束,或调用了当前线程的interrupt()时,当前线程从TIMED_WAITING -->RUNNABLE ##### 情况7 RUNNABLE <–> TIMED_WAITING + 当前线程调用 Thread.sleep(long n)方法时,当前线程从 RUNNABLE --> TIMED_WAITING + 当前线程等待时间超过了n毫秒,当前线程从TIMED_WAITING -->RUNNABLE ##### 情况8 RUNNABLE <–> TIMED_WAITING + 当前线程调用 `LockSupport.parkNanos(long nanos)`或`LockSupport.parkUntil(long millis)`方法时,当前线程从 RUNNABLE --> TIMED_WAITING + 调用`LockSupport.unpark(目标线程)`或调用了线程的`inturrept()`方法,或者等待超时,目标线程从TIMED_WAITING -->RUNNABLE ##### 情况9 RUNNABLE <–> BLOCKED + t线程用 synchronized(obj)获取了对象锁,竞争失败时,从 RUNNABLE --> BLOCKED + 持obj锁线程的同步代码块执行完毕,会唤醒改对象上所有BLOCKED的线程重新竞争,如果t线程竞争成功,t线程从BLOCKED-->RUNNABLE,其他线程仍然BLOCKED ##### 情况10 RUNNABLE --> TERMINATED + 当线程所有代码执行完毕,进入TERMINATED #### 示例 ```java /* * 演示 java 线程的 6 种状态(NEW, RUNNABLE, TERMINATED, BLOCKED, WAITING, TIMED_WAITING) * */ @Slf4j(topic = "c.Test15") public class Test15 { public static void main(String[] args) { // NEW //新建一个对象,没有start 所以此时是NEW状态 Thread t1 = new Thread(() -> { log.info("NEW 状态"); }, "t1"); // RUNNABLE // 创建对象后,并且start启动了线程,线程用了while死循环,一直在占用cpu,所以此时是RUNNABLE状态 Thread t2 = new Thread(() -> { while (true) { } }, "t2"); t2.start(); // TERMINATED // 创建对象后,并且start启动了线程,但是代码瞬间执行完毕,cpu用完就释放了,所以是TERMINATED状态 Thread t3 = new Thread(() -> { log.info("running"); }, "t3"); t3.start(); // TIMED_WAITING // 此线程调用了sleep方法将该线程暂时睡眠,所以又成为有时间的等待,时间一过就会恢复,所以是TIMED_WAITING 状态 Thread t4 = new Thread(() -> { synchronized (Test15.class) { try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } }, "t4"); t4.start(); // WAITING // 该线程调用了 t2 线程的join方法,但是线程2是死循环,一直不会停止, // 所以该线程需要等线程2执行完毕才能继续执行,又称为需要等待其他线程做出改变的动作,所以是 WAITING 状态 Thread t5 = new Thread(() -> { try { t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } }, "t5"); t5.start(); // BLOCKED // 线程6和线程4有一个共同的特点就是给Test15.class进行了加锁,线程4的执行时间比较长, // 锁被线程4掌握,这个时候线程6就会拿不到锁也就进人了BLOCKED状态 Thread t6 = new Thread(() -> { synchronized (Test15.class) { try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } }, "t6"); t6.start(); // 主线程休眠 1 秒, 目的是为了等待 t3 线程执行完 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } log.info("t1 线程状态: {}", t1.getState()); log.info("t2 线程状态: {}", t2.getState()); log.info("t3 线程状态: {}", t3.getState()); log.info("t4 线程状态: {}", t4.getState()); log.info("t5 线程状态: {}", t5.getState()); log.info("t6 线程状态: {}", t6.getState()); } } ``` **运行结果** ``` 10:53:48.656 c.Test15 [t3] - running 10:53:49.661 c.Test15 [main] - t1 线程状态: NEW 10:53:49.662 c.Test15 [main] - t2 线程状态: RUNNABLE 10:53:49.662 c.Test15 [main] - t3 线程状态: TERMINATED 10:53:49.662 c.Test15 [main] - t4 线程状态: TIMED_WAITING 10:53:49.662 c.Test15 [main] - t5 线程状态: WAITING 10:53:49.662 c.Test15 [main] - t6 线程状态: BLOCKED ``` **几种方法的比较:** + **`Thread.sleep(long millis)`**:一定是当前线程调用此方法,当前线程进入TIMED_WAITING状态,但不释放对象锁,millis后线程自动苏醒进入就绪状态。 + **作用**:给其它线程执行机会的最佳方式。 + **`Thread.yield()`**:一定是当前线程调用此方法,当前线程放弃获取的CPU时间片,但不释放锁资源,由运行状态变为就绪状态,让OS再次选择线程。 + **作用**:让相同优先级的线程轮流执行,但并不保证一定会轮流执行。实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。`Thread.yield()`不会导致阻塞。该方法与sleep()类似,只是不能由用户指定暂停多长时间。 + **`t.join()/t.join(long millis)`**:当前线程里调用其它线程t的join方法,当前线程进入WAITING/TIMED_WAITING状态,当前线程不会释放已经持有的对象锁。线程t执行完毕或者millis时间到,当前线程进入就绪状态。 + **`obj.wait()`**:当前线程调用对象的wait()方法,当前线程释放对象锁,进入等待队列。依靠`notify()/notifyAll()`唤醒或者wait(long timeout) timeout时间到自动唤醒。 + **`obj.notify()`**:唤醒在此对象监视器上等待的单个线程,选择是任意性的。`notifyAll()`唤醒在此对象监视器上等待的所有线程。 *附参考文章链接* *https://blog.csdn.net/weixin_70298631/article/details/125713577* *https://www.runoob.com/note/34745*
标签:
并发编程
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/2467.html
上一篇
07.并发编程之守护线程
下一篇
09.并发编程之共享问题
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
Sentinel
散列
Ubuntu
Spark
工具
稀疏数组
GET和POST
Scala
Hive
JavaWEB项目搭建
Nacos
人工智能
DataWarehouse
VUE
Kafka
Quartz
随笔
Spark RDD
链表
Spark Streaming
算法
Netty
队列
SpringCloudAlibaba
字符串
Stream流
正则表达式
MyBatis-Plus
JavaSE
Git
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭