当前位置: 首页 > news >正文

Java线程的6种状态和JVM状态打印

原文网址:Java线程的6种状态和JVM状态打印-CSDN博客

简介

本文介绍Java线程的6种状态和JVM状态。

Java线程的6种状态

1. NEW:初始状态

线程被创建(比如new Thread()),但还没调用start()方法。

2. RUNNABLE:运行状态

这两种都是运行状态:就绪或正在运行。调用start()后进入此状态。

3. BLOCKED:阻塞状态

表示线程在等“锁”(监视器锁(monitor lock)),比如synchronized锁。

4. WAITING:无限等待状态

等其他线程通知或中断,才能执行。

以下方法调用后会进入此状态:

  • 调用 Object.wait() 且不带超时
  • 调用 Thread.join() 且不带超时
  • 调用 LockSupport.park()

5. TIMED_WAITING:限时等待

在指定时间内等待另其他线程执行特定操作。

以下方法调用后会进入此状态:

  • 调用 Thread.sleep(long)
  • 调用 Object.wait(long)
  • 调用 Thread.join(long)
  • 调用 LockSupport.parkNanos(long) / parkUntil(long)

6. TERMINATED:终止状态

线程执行结束(成功执行或异常结束)。

Java线程状态切换

1. NEW-> RUNNABLE

状态描述:当使用 new Thread() 创建一个线程对象后,该线程就处于 NEW 状态,此时,它仅仅是一个Java对象,JVM尚未为其分配任何系统资源,也未与操作系统底层的线程关联。

触发状态转换:调用线程对象的 start() 方法

细节:调用后,JVM会向操作系统申请创建一个对应的原生线程,并将其纳入操作系统的线程调度器管理,线程状态变为 RUNNABLE。进入RUNNABLE并不意味着立刻执行,只是表示“可以被CPU执行了”,具体何时执行取决于操作系统的调度。

2. RUNNABLE <-> BLOCKED

状态描述:BLOCKED 状态与 synchronized 关键字(即监视器锁 Monitor)强相关。

RUNNABLE -> BLOCKED

触发状态转换:线程尝试进入一个 synchronized 修饰的同步代码块或方法,但该代码块的监视器锁已被其他线程持有。

细节:获取锁失败的线程会进入该锁的阻塞队列 (Entry Set),状态变为 BLOCKED,处于此状态的线程不会占用CPU时间。

BLOCKED -> RUNNABLE

触发状态转换:持有该监视器锁的线程释放了锁(即退出了同步代码块)。

细节:操作系统会从该锁的阻塞队列中,按照一定规则(可能是公平或非公平)唤醒一个或多个 BLOCKED 状态的线程,让它们重新去竞争锁,被唤醒的线程状态变回 RUNNABLE,但只有成功竞争到锁的线程才能执行。

3. RUNNABLE <-> WAITING / TIMED_WAITING

这两个状态都表示线程在等待,区别在于有无时间限制

RUNNABLE -> WAITING

触发状态转换:线程在持有锁的情况下,调用了不带超时的 Object.wait()、Thread.join() 或 LockSupport.park()。

Object.wait() 细节(这是典型场景):线程必须先持有对象的监视器锁,才能调用该对象的 wait() 方法,调用后,线程会立即释放持有的锁,并进入该对象的等待集合 (Wait Set),状态变为 WAITING,此状态同样不占用CPU。

RUNNABLE -> TIMED_WAITING

触发状态转换:与 WAITING 类似,但调用的是带超时参数的方法,如 Thread.sleep(long)、Object.wait(long)、Thread.join(long) 等。

Thread.sleep(long) 细节(这是特殊情况):调用 sleep 方法会让线程进入 TIMED_WAITING 状态,但它不释放它已持有的锁,这是 sleep 和 wait 的一个核心区别。

Object.wait(long) 细节:与 wait() 类似,调用后会释放锁并进入等待集合,但它有一个最长等待时间。

WAITING / TIMED_WAITING -> RUNNABLE / BLOCKED

触发状态转换:对于 WAITING 状态的线程(由 wait() 导致),等待另一个线程在同一个对象上调用 Object.notify() 或 Object.notifyAll()。

TIMED_WAITING 状态的线程,除了上述 notify/notifyAll 唤醒外,等待时间超时也会自动唤醒。

【面试重点细节】:被唤醒的线程不会立刻恢复到 RUNNABLE 状态,它会从等待集合 (Wait Set) 移动到阻塞队列 (Entry Set),状态变为 BLOCKED,然后重新去竞争锁,只有当它再次成功获取到锁之后,才会从 BLOCKED 状态转换回 RUNNABLE 状态继续执行。

4. RUNNABLE -> TERMINATED

状态描述:线程的使命终结。

触发状态转换:

  • 线程的 run() 方法正常执行完毕,自然退出
  • run() 方法因未捕获的异常而意外终止

细节:一旦线程进入 TERMINATED 状态,它的生命周期就结束了,不能再通过调用 start() 方法使其复活,此时,与操作系统底层的线程关联也会被取消。

JVM状态打印

状态大全

Deadlock

表示有死锁

Waiting on condition

含义:它在等待其他资源把自己唤醒,或者是它是调用了 sleep(N)。

此时状态:WAITING || TIMED_WAITING。

举例:

java.lang.Thread.State: WAITING (parking):一直等某个条件发生
java.lang.Thread.State: TIMED_WAITING (parking或sleeping):设有超时时间,那个条件不到来,也将定时唤醒自己。

如果大量线程在“waiting on condition”,可能是它们又跑去获取第三方资源,尤其是第三方网络资源,迟迟获取不到Response,导致大量线程进入等待状态。

waiting for monitor entry

含义:它在等待进入一个临界区 ,所以它在”Entry Set“队列中等待。

此时状态:BLOCKED

举例:java.lang.Thread.State: BLOCKED (on object monitor)

知识点:注意 “Entry Set” 就是咱们平时经常使用synchronized 的时候线程所等待的区域。

如果大量线程在 “waiting for monitor entry”,可能是一个全局锁阻塞住了大量线程。如果短时间内多次打印的 thread dump 文件反映,随着时间流逝,waiting for monitor entry 的线程越来越多,没有减少的趋势,可能意味着某些线程在临界区里呆的时间太长了,以至于越来越多新线程迟迟无法进入临界区。

in Object.wait()

含义:说明它获得了监视器锁之后(也就是进入synchronized方法块),又调用了 java.lang.Object.wait() 方法。

每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。在 “Entry Set”中等待的线程状态是 “Waiting for monitor entry”,而在 “Wait Set”中等待的线程状态是 “in Object.wait()”。
当线程获得了 Monitor,如果发现线程继续运行的条件没有满足,它则调用对象(一般就是被 synchronized 的对象)的 wait() 方法,放弃了 Monitor,进入 “Wait Set”队列。

此时状态:TIMED_WAITING || WAITING

举例:

java.lang.Thread.State: TIMED_WAITING (on object monitor);
java.lang.Thread.State: WAITING (on object monitor);

查看状态的方法

可以打印出JVM里线程的状态,方法有以下几种:

  1. jstack
  2. jconsole
  3. VisualVM

以上方法都能做到:展示每个线程的状态(比如BLOCKED (on object monitor)、WAITING (parking)等),还能看到线程在等什么锁、在哪行代码阻塞。

比如:

“RMI TCP Connection(idle)” daemon prio=10 tid=0x00007fd50834e800 nid=0x56b2 waiting on condition [0x00007fd4f1a59000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
parking to wait for <0x00000000acd84de8> (a java.util.concurrent.SynchronousQueueTransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)
at java.util.concurrent.SynchronousQueueTransferStack.awaitFulfill(SynchronousQueue.java:424)atjava.util.concurrent.SynchronousQueueTransferStack.awaitFulfill(SynchronousQueue.java:424) at java.util.concurrent.SynchronousQueueTransferStack.awaitFulfill(SynchronousQueue.java:424)atjava.util.concurrent.SynchronousQueueTransferStack.transfer(SynchronousQueue.java:323)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:874)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945)
at java.util.concurrent.ThreadPoolExecutorWorker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:662)

http://www.lryc.cn/news/623485.html

相关文章:

  • Vue深入组件:Props 详解3
  • 2.Pod理论
  • Golang database/sql 包深度解析(二):连接池实现原理
  • 云原生俱乐部-RH134知识点总结(3)
  • PyCharm与前沿技术集成指南:AI开发、云原生与大数据实战
  • Spring Boot 项目配置 MySQL SSL 加密访问
  • Debug马拉松:崩溃Bug的终极挑战
  • 本地处理不上传!隐私安全的PDF转换解决方案
  • 华为云之Linux系统安装部署Tomcat服务器
  • Git 命令指南:从 0 到熟练、从常用到“几乎全集”(含常见报错与解决)建议收藏!!!
  • LintCode第137-克隆图
  • 学习游戏制作记录(玩家掉落系统,删除物品功能和独特物品)8.17
  • 《设计模式》工厂方法模式
  • 代码随想录算法训练营四十四天|图论part02
  • 天地图开发的优点
  • The Network Link Layer: 无线传感器中Delay Tolerant Networks – DTNs 延迟容忍网络
  • GANs生成对抗网络生成手写数字的Pytorch实现
  • VS Code配置MinGW64编译Apache Arrow C++库
  • 【k8s、docker】Headless Service(无头服务)
  • python+flask后端开发~项目实战 | 博客问答项目--模块化文件架构的基础搭建
  • C++算法题目分享:二叉搜索树相关的习题
  • 【前端基础】flex布局中使用`justify-content`后,最后一行的布局问题
  • ubuntu 24.04 安装
  • Android RxJava线程调度与性能优化指南
  • (一)前端面试(cookie/)
  • PostgreSQL导入mimic4
  • 数据结构代码分享-1 顺序表
  • 简单的 VSCode 设置
  • Oracle algorithm的含义
  • 基于Vue + Node能源采购系统的设计与实现/基于express的能源管理系统#node.js