Java线程
线程
Java线程状态
- Java线程在其生命周期中会经历不同的状态,Java语言在Thread.State枚举中明确定义了6种线程状态:
public enum State {
NEW, // 线程尚未启动。 此时线程对象已存在,但还没有调用start()方法。
RUNNABLE, // 线程正在运行或等待系统资源。 RUNNABLE转换条件:调用线程的start()方法。
BLOCKED, // 线程等待监视器锁
WAITING, // 线程无限期等待其他线程执行特定动作
TIMED_WAITING, // 线程等待指定时间
TERMINATED; // 线程已执行完毕
}
TIMED_WAITING进入方式:
(1)Thread.sleep(long)
(2)Object.wait(long)
(3)Thread.join(long)
(4)LockSupport.parkNanos()
(5)LockSupport.parkUntil()
BLOCKED进入方式:
等待进入synchronized方法/块
synchronized(lock) { // 如果其他线程持有lock,当前线程会进入BLOCKED状态 // 获取到锁后进入RUNNABLE状态 }特点:
必须有两个以上线程竞争同一把锁才会出现
不消耗CPU资源
不可中断
比较 BLOCKED与TIMED_WAITING:
TIMED_WAITING:由sleep()、wait(timeout)等方法引起,是主动等待
BLOCKED:由锁竞争引起,是被动阻塞
WAITING(无限期等待状态)进入方式:
调用
Object.wait()调用
Thread.join()调用
LockSupport.park()
TERMINATED状态:
含义:线程执行完毕(run()方法正常结束)或因异常退出后的状态。
进入TERMINATED状态
(1)、正常完成执行
new Thread(() -> {
System.out.println("执行任务...");
// run()方法自然结束
}).start();
(2)、抛出未捕获的异常
new Thread(() -> {
throw new RuntimeException("意外错误");
}).start();
注意:
一旦进入TERMINATED状态,线程就不能再次启动,具有不可逆性;
线程栈等资源会被JVM回收,但Thread对象本身仍然存在;
可通过getState()方法检测,isAlive()方法返回false
TERMINATED状态与其他状态的关系
NEW → RUNNABLE → (BLOCKED/WAITING/TIMED_WAITING) → RUNNABLE → TERMINATED
总结
状态变化简易图
实例化
│
▼
NEW (新建)
│
│ Thread.start()
▼
┌─────────────┐
│ RUNNABLE │◄──────────────────────┐
│ (可运行) │ │
├─────┬───────┤ │
│READY│RUNNING│ │
└─────┴───────┘ │
│ │ │
│ │ 竞争锁失败 │
│ ▼ │
│ BLOCKED (阻塞) │
│ │ │
│ │ 获取到锁 │
│ ▼ │
│ wait()/join()/park() notify()/unpark()
▼ │ │
WAITING (无限等待) │
│ │ │
│ │ sleep(timeout)/wait(timeout)│
▼ ▼ │
TIMED_WAITING (超时等待) │
│ │ │
│ │ 超时/被唤醒 │
└────┴────────────────────────────┘
│
│ 执行完成
▼
TERMINATED (终止)
Java线程状态2
java线程的五大状态,阻塞状态详解_线程阻塞状态-CSDN博客

- 每一个对象都有一个无形的锁,sleep不会释放锁。(也就是我们说过的,抱着资源睡觉,这个特点对比wait)
JVisualVm显示线程状态1

jVisualVM 在 Java 标准状态的基础上进一步细分(尤其是阻塞状态):
| jVisualVM 状态 | jVisualVM显示 | 对应 Java 状态 | 详细说明 |
|---|---|---|---|
| RUNNABLE | 运行 | RUNNABLE |
线程正在执行或可运行。 |
| WAITING | 等待(先持有锁) | WAITING |
通用等待状态,可能由 Object.wait() 或 LockSupport.park() 触发。 |
| PARKED | 驻留(不需要锁) | WAITING |
线程调用 LockSupport.park() 进入的等待状态(显示为 WAITING (parking))。 |
| BLOCKED | 监视 | BLOCKED |
线程等待进入 synchronized 块(显示为 BLOCKED (on object monitor))。 |
| MONITOR | 监视(锁机制的统称) | BLOCKED/WAITING |
与监视器锁相关的状态(如竞争锁或调用 wait() 后释放锁)。 |
| TIMED_WAITING | 休眠(支持外部唤醒和锁释放) | TIMED_WAITING |
限时等待(如 sleep()、LockSupport.parkNanos())。 |
| SLEEPING | 休眠(仅超时唤醒,不释放锁) | TIMED_WAITING |
线程调用 Thread.sleep() 进入的状态(jVisualVM 可能单独标记)。 |
| 结束 | 结束:空白的为结束 | TERMINATED |
线程执行完毕(run()方法正常结束)或因异常退出后的状态。 |
一句话记忆:
sleep()是“闹钟”,到点才醒;
TIMED_WAITING是“待机模式”,可被提前叫醒。
关键区别与说明
PARKED是WAITING的子集- Java 标准状态中,
LockSupport.park()触发的阻塞归类为WAITING。 - 但 jVisualVM 会明确标记为
PARKED(显示为WAITING (parking)),便于区分传统的Object.wait()。
- Java 标准状态中,
MONITOR状态- 在 Java 中,
synchronized锁竞争导致BLOCKED,而wait()导致WAITING。 - jVisualVM 可能统一标记为
MONITOR,或在堆栈中注明on object monitor。
- 在 Java 中,
SLEEPING是TIMED_WAITING的特例Thread.sleep()在 Java 中属于TIMED_WAITING,但 jVisualVM 可能单独显示为SLEEPING。
关键对比
| 状态 | 触发方法 | CPU 占用 | 唤醒条件 | 典型场景 |
|---|---|---|---|---|
| 休眠 | Thread.sleep() |
0% | 超时结束 | 定时任务、模拟延迟 |
| 驻留 | LockSupport.park() |
0% | 调用 unpark() |
线程池空闲等待、AQS 锁实现 |
| 监视-BLOCKED | synchronized 竞争失败 |
0% | 锁释放 | 高并发锁竞争 |
| 监视-WAITING | Object.wait() |
0% | notify()/notifyAll() |
生产者-消费者模型 |
线程的状态对比:等待、驻留、监视
线程的状态对比:等待、驻留、监视 - deyang - 博客园
JVisualVm显示线程状态2
JVisualVM 中线程状态(运行/休眠/等待/驻留/监视)解析
jVisualVM显示线程状态:

- 运行(runnable):正在运行中的线程。
- 休眠(timed_waiting):休眠线程,例如调用Thread.sleep方法。
- 等待(waiting):等待唤醒的线程,可通过调用Object.wait方法获得这种状态,底层实现是基于对象头中的monitor对象。
- 驻留(waiting):等待唤醒的线程,和等待状态类似,只不过底层的实现方式不同,处于这种状态的例子有线程池中的空闲线程,等待获取reentrantLock锁的线程,调用了reentrantLock的condition的await方法的线程等等,底层实现是基于Unsafe类的park方法,在AQS中有大量的应用。
- 监视(blocked):等待获取monitor锁的线程,例如等待进入synchronize代码块的线程。
JVisualVm显示线程
JVisualVm显示线程的线程不完整,想看所有的线程使用 jstack

主要系统线程
- main - 主线程,执行程序的 main() 方法
- Reference Handler - 处理引用对象的线程(如软引用、弱引用等)
- Finalizer - 调用对象的 finalize() 方法的线程
- Signal Dispatcher - 处理操作系统发送给 JVM 信号的线程
- Attach Listener - 用于接收外部工具(如 jvisualvm)连接的线程
垃圾回收相关线程
JVisualVm线程界面未显示GC线程,点线程dump可以看到
- GC 线程(名称可能不同):
- "GC Thread#0"、"GC Thread#1" 等
- 执行垃圾收集操作的线程
- 数量和名称取决于使用的垃圾收集器
- VM Thread - JVM 系统线程,执行虚拟机操作
其他常见线程
-
CompilerThread0/1 - JIT 编译线程,将字节码编译为本地代码
-
JDWP Command Reader - Java Debug Wire Protocol (JDWP) 的工作线程
-
调试通信:在 Java 调试过程中,负责读取来自调试器(如 IntelliJ IDEA、Eclipse、jdb)的调试命令。
-
协议处理:解析 JDWP 协议数据包,并将调试指令传递给 JVM 的调试子系统。
-
触发条件:该线程仅在以下场景出现:
-
-
主动启用调试模式:通过 JVM 参数
-agentlib:jdwp=...启动调试功能。java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar app.jar -
IDE 调试时:当使用 IntelliJ/Eclipse 的调试功能时,IDE 会自动附加到目标进程并激活 JDWP。
-
-
-
**Service Thread ** - JVM 内部服务:负责执行 JVM 的底层后台任务,例如:
- 垃圾回收(GC)相关的辅助操作(如并发标记阶段的处理)。
- 动态代码反优化(Deoptimization)的清理工作。
- 其他 JVM 内部维护任务(如方法编译队列的处理)。
-
VM Periodic Task Thread - 该线程负责执行 JVM 内部的周期性任务,包括但不限于:
- 性能监控数据采集(如 JVM 统计信息、性能计数器更新)
- 动态代码优化/去优化(如 JIT 编译后的代码调整)
- 内存管理辅助任务(如某些 GC 算法的后台维护)
- 其他 JVM 内部定期维护任务(如检查死锁、调整线程优先级)
-
Monitor Ctrl-Break - 是一个由 IntelliJ IDEA(或其他一些 Java IDE)在运行或调试 Java 程序时自动创建的辅助线程,主要用于 监控用户输入(如 Ctrl+C 或 Ctrl+Break),以便在控制台程序被强制终止时执行清理操作(如关闭资源、生成线程转储等)。
-
常见的 JMX 相关线程。在
jstack或jvisualvm中,你可能会看到以下 JMX 相关的线程:线程名称 作用 RMI TCP Connection处理 JMX 客户端(如 JConsole、VisualVM)的远程连接请求。 RMI Scheduler调度 RMI(Remote Method Invocation)相关任务。 JMX server connection负责 JMX 服务端的连接管理(如 com.sun.jmx.remote.internal.ServerCommunicatorAdmin)。RMI RenewClean清理过期的 RMI 连接(租约续订机制)。 RMI GC DaemonRMI 分布式垃圾回收(DGC)相关的线程。 RMI TCP Accept监听 JMX/RMI 的 TCP 连接请求(通常在端口 1099或自定义端口)。-
这样线程出现的情况:
-
当启用 JMX 远程监控时,例如:
java -Dcom.sun.management.jmxremote.port=9010 \ -Dcom.sun.management.jmxremote.authenticate=false \ -Dcom.sun.management.jmxremote.ssl=false \ -jar myapp.jar此时 JVM 会启动 RMI 和 JMX 相关线程 以支持远程管理。
-
即使未进行启动配置jmx,JVisualVm本地连接java进程时,也会启动这些线程。
-
-
-
WatcherThread - 监控 JVM 状态的线程
-
Common-Cleaner - 用于清理资源的线程(Java 9+)
守护线程
如何区分守护线程 vs 用户线程?
| 特征 | 守护线程(如 VM Thread) | 用户线程(如 main) |
|---|---|---|
| 阻止 JVM 退出? | ❌ 不会 | ✅ 会 |
| 创建者 | JVM 内部创建 | 用户代码或默认线程(如 main) |
| 典型例子 | GC 线程、JMX 线程、VM Thread | main、自定义未设 setDaemon 的线程 |
| jstack 标记 | 可能显示 daemon(部分 JVM 版本省略) |
无 daemon 标记 |
上面列举的那么多线程:主要系统线程、垃圾回收相关线程、其他常见线程。只有main线程是用户线程,其他都是守护线程
jstack打印细节解析
"main" #1 prio=5 os_prio=0 tid=0x0000000003693800 nid=0xc50 waiting on condition [0x000000000311f000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.sh.demo.Test.main(Test.java:29)
Locked ownable synchronizers:
- None
1. 线程名称
"main"
- 表示这是 Java 主线程,即执行
public static void main(String[] args)的线程。
2. 线程编号
#1
- 该线程在 JVM 中的 内部编号(第一个创建的线程)。
3. 线程优先级
prio=5
- Java 线程优先级(范围:1~10,默认是 5)。
- Java 线程优先级是数值越大优先级越高(1~10 ,10最高),但实际效果依赖操作系统调度,通常不建议依赖优先级控制线程行为。
- 注意:Java 的优先级不一定完全映射到操作系统优先级。
4. 操作系统优先级
os_prio=0
- 操作系统级别的线程优先级(具体含义依赖 OS)。
- 在 Linux 中,
0表示普通优先级。
5. 线程 ID(Java 内部标识)
tid=0x0000000003693800
- JVM 内部的线程对象地址(十六进制),用于唯一标识该线程。
6. 原生线程 ID(操作系统层)
nid=0xc50
- Native Thread ID(十六进制),对应操作系统的线程 ID。
- 转换十进制:
0xc50=3152(可通过top -H -p <PID>查看该线程的 CPU 占用)。
7. 线程状态
waiting on condition [0x000000000311f000]
- 等待条件:线程因某种原因(如
sleep、wait、LockSupport.park)进入等待状态。 [0x000000000311f000]:线程栈的起始内存地址(通常无需关注)。
8. Java 线程状态
java.lang.Thread.State: TIMED_WAITING (sleeping)
TIMED_WAITING:线程正在执行 限时等待。(sleeping):具体原因是通过Thread.sleep()进入等待状态。
9. 调用堆栈
at java.lang.Thread.sleep(Native Method)
at com.sh.demo.Test.main(Test.java:29)
- 堆栈轨迹:
- 当前正在执行
Thread.sleep()(Native 方法,由 JVM 实现)。 - 调用来源:
Test.main()方法的第 29 行(代码中显式调用了sleep)。
- 当前正在执行
10. 持有的锁
Locked ownable synchronizers: - None
- 未持有任何显式锁(如
ReentrantLock)。 - 如果是
synchronized锁,不会在此显示(需看其他线程的BLOCKED状态)。
浙公网安备 33010602011771号