Java 线程的几种状态及状态间转换

Java并发知识体系持续更新:https://blog.csdn.net/m0_46144826/category_9881831.html


操作系统层面,线程有以下状态:

计算机层面的线程状态转换

这五种状态是最基本的转换模型。在不同的编程语言中,会有细微区别。

Java线程状态转换图

Java 来说,线程状态已经确定在了 Thread 内部类的枚举中:

public enum State {
        NEW,//尚未启动的线程的线程状态
        RUNNABLE,//可运行线程的线程状态。处于可运行状态的线程正在Java虚拟机中执行,但可能正在等待来自操作系统的其他资源,例如处理器。
        BLOCKED,//阻塞状态
        WAITING,//等待线程的线程状态
        TIMED_WAITING,//具有指定等待时间的等待线程的线程状态
        TERMINATED;//终止线程的线程状态。线程已完成执行。
    }

Blocking、 Waiting、Timed Waiting 其实都是休眠状态,在 Java 中进行了区分。

可运行状态和运行状态合并成 Runnable。

然后看看详细介绍

  1. New(新建)

线程对象被创建时,它只会短暂地处于这种状态。此时它已经分配了必须的系统资源,并执行了初始化。

相当于,这个线程还没有调用 start() 方法。


  1. Runnable(可运行/就绪/运行中)

Runnable 状态包括了操作系统线程状态中的 Running 和 Ready,也就是处于此状态的线程可能正在运行,也可能正在等待系统资源,如等待 CPU 为它分配时间片,如等待网络IO读取数据。

线程调度程序会从可运行线程池中选择一个线程作为当前线程。这也是线程进入运行状态的唯一一种方式。

所以线程只能从,可运行状态进入运行中状态。

  • 调用线程的 start() 方法,此线程进入就绪状态。
  • 当前线程时间片用完了,调用当前线程的 yield() 方法,当前线程进入就绪状态。
  • 锁池里的线程拿到对象锁后,进入就绪状态。
  • 当前线程 sleep()方法结束,其他线程 join() 结束,等待用户输入完毕,某个线程拿到对象锁,这些线程也将进入就绪状态。

  1. Blocking(阻塞)

Blocking 称为阻塞状态,或者说线程已经被挂起,原因通常是它在等待一个“锁”,当尝试进入一个 synchronized 语句块/方法时,锁已经被其它线程占有,就会被阻塞,直到另一个线程走完临界区或发生了相应锁对象的 wait() 操作后,它才有机会去争夺进入临界区的权利。

在 Java 代码中,需要考虑 synchronized 的粒度问题,否则一个线程长时间占用锁,其它争抢锁的线程会一直阻塞,直到拥有锁的线程释放锁。

处于 BLOCKED 状态的线程,即使对其调用 thread.interrupt() 也无法改变其阻塞状态,因为 interrupt() 方法只是设置线程的中断状态,即做一个标记,不能唤醒处于阻塞状态的线程。


  1. Waiting(无限期等待)

等待其它线程显式地唤醒,否则不会被分配 CPU 时间片。

进入方法退出方法
没有设置 Timeout 参数的 Object.wait() 方法Object.notify() / Object.notifyAll()
没有设置 Timeout 参数的 Thread.join() 方法被调用的线程执行完毕
LockSupport.park() 方法-

  1. Timed Waiting(限期等待)

无需等待其它线程显式地唤醒,在一定时间之后会被系统自动唤醒。

调用 Thread.sleep() 方法使线程进入限期等待状态时,常常用“使一个线程睡眠”进行描述。

调用 Object.wait() 方法使线程进入限期等待或者无限期等待时,常常用“挂起一个线程”进行描述。

睡眠和挂起是用来描述行为,而阻塞和等待用来描述状态。

阻塞和等待的区别在于,阻塞是被动的,它是在等待获取一个排它锁。而等待是主动的,通过调用 Thread.sleep()Object.wait() 等方法进入。

进入方法退出方法
Thread.sleep() 方法时间结束
设置了 Timeout 参数的 Object.wait() 方法时间结束 / Object.notify() / Object.notifyAll()
设置了 Timeout 参数的 Thread.join() 方法时间结束 / 被调用的线程执行完毕
LockSupport.parkNanos() 方法-
LockSupport.parkUntil() 方法-

  1. Terminated(死亡)

可以是线程结束任务之后自己结束,或者产生了异常而结束。

其实这只是 Java 语言级别的一种状态,在操作系统内部可能已经注销了相应的线程,或者将它复用给其他需要使用线程的请求,而在 Java 语言级别只是通过 Java 代码看到的线程状态而已。


“阻塞”与“等待”的区别:

(1)“阻塞”状态是等待着获取到一个排他锁,进入“阻塞”状态都是被动的,离开“阻塞”状态是因为其它线程释放了锁,不阻塞了;

(2)“等待”状态是在等待一段时间 或者 唤醒动作的发生,进入“等待”状态是主动的;

如主动调用 Object.wait() ,如无法获取到 ReentraantLock ,主动调用 LockSupport.park() ,如主线程主动调用 subThread.join() ,让主线程等待子线程执行完毕再执行。

离开“等待”状态是因为其它线程发生了唤醒动作或者到达了等待时间。


参考文章

https://www.cnblogs.com/javadevelper/p/6036472.html

https://www.pdai.tech/md/java/thread/java-thread-x-thread-basic.html

https://blog.csdn.net/qq_33565047/article/details/102958254

https://blog.csdn.net/wanliguodu/article/details/81005560

https://www.cnblogs.com/trust-freedom/p/6606594.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值