import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.SneakyThrows;
public class ReadStackLog {
public static void main(String[] args) throws JsonProcessingException {
new Thread(new TimeWaiting (), "TimeWaitingThread").start();
new Thread(new Waiting(), "WaitingThread").start();
// 使用两个Blocked线程,一个获取锁成功,另一个被阻塞
new Thread(new Blocked(), "BlockedThread-1").start();
new Thread(new Blocked(), "BlockedThread-2").start();
}
}
// 该线程不断地进行睡眠
class TimeWaiting implements Runnable {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
// 该线程在Waiting.class实例上等待; 该线程进入等待状态(WAITING),等待一个对象的通知。
class Waiting implements Runnable {
@Override
public void run() {
while (true) {
synchronized (Waiting.class) {
try {
Waiting.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
// 该线程在Blocked.class实例上加锁后,不会释放该锁
class Blocked implements Runnable {
@SneakyThrows
public void run() {
synchronized (Blocked.class) {
while (true) {
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
程序功能概述
这个程序主要启动了四个线程,每个线程模拟不同的线程状态:
- TimeWaitingThread: 该线程不断地进入睡眠状态(
TIMED_WAITING)。 - WaitingThread: 该线程进入等待状态(
WAITING),等待一个对象的通知。 - BlockedThread-1 和 BlockedThread-2: 这两个线程尝试获取同一个锁(
Blocked.class)。由于BlockedThread-1先获得锁,BlockedThread-2将一直被阻塞(BLOCKED)。
代码详解
- 主方法 (
main):启动四个线程,每个线程对应一个不同的任务。 - TimeWaiting 类:
- 该线程在
run方法中进入一个无限循环,每次循环调用Thread.sleep(1000000),即让线程进入睡眠状态。 - 这种状态在 Java 中被称为
TIMED_WAITING,表示线程在等待一段时间后会自动恢复运行。
- 该线程在
- Waiting 类:
- 该线程在
run方法中进入一个无限循环,首先获得Waiting.class的锁(同步块),然后调用Waiting.class.wait()使线程进入等待状态。 wait()方法会使线程释放锁,并进入等待状态,直到有其他线程调用同一个锁的notify()或notifyAll()方法(在此程序中没有其他线程,因此该线程将一直等待)。- 这种状态在 Java 中被称为
WAITING。
- 该线程在
- Blocked 类:
- 该线程在
run方法中首先尝试获取Blocked.class的锁(同步块)。 - 第一个启动的
BlockedThread-1获得锁并进入无限睡眠状态。 - 第二个启动的
BlockedThread-2尝试获取相同的锁,但由于锁已被BlockedThread-1持有,它将被阻塞,直到锁被释放。 - 这种被阻塞等待锁的状态在 Java 中称为
BLOCKED。
- 该线程在
2. 命令行工具 jps 和 jstack 的作用
jps 工具
jps(Java Virtual Machine Process Status Tool)是 JDK 提供的一个工具,用于列出当前系统上正在运行的 Java 应用进程。它的输出包括每个 Java 进程的进程ID(PID)和主类名。
你运行的命令和输出示例如下:
D:\B_IDEA\testE_09\verifyRedisCache>jps
49060
40860 Jps
49580 ReadStackLog
51148 Launcher
- 49060:可能是一个没有主类名的 Java 进程。
- 40860 Jps:
jps工具本身的进程ID。 - 49580 ReadStackLog:你刚才编写并运行的
ReadStackLog程序的进程ID。 - 51148 Launcher:可能是其他 Java 应用程序的进程。
jstack 工具
jstack(Java Stack Trace)用于获取指定 Java 进程的线程堆栈信息。它可以帮助开发者分析线程的状态、死锁等问题。
你运行的命令和部分输出如下:
D:\B_IDEA\testE_09\verifyRedisCache>jstack 49580
...
这里,49580 是 ReadStackLog 程序的进程ID。
3. jstack 输出的线程信息详解
以下是 jstack 输出的部分内容及其解释:
主要线程分析
- TimeWaitingThread (#20)
"TimeWaitingThread" #20 prio=5 os_prio=0 tid=0x000002535c3fb000 nid=0xaaf0 waiting on condition [0x000000cd0c3ff000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at TimeWaiting.run(ReadStackLog.java:20)
at java.lang.Thread.run(Thread.java:750)
状态:TIMED_WAITING,表示线程在 sleep 方法中进入了睡眠状态。
原因:调用 Thread.sleep(1000000) 进入睡眠。
2. WaitingThread (#21)
"WaitingThread" #21 prio=5 os_prio=0 tid=0x000002535c40e800 nid=0xb420 in Object.wait() [0x000000cd0c4ff000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at Waiting.run(ReadStackLog.java:34)
at java.lang.Thread.run(Thread.java:750)
状态:WAITING,表示线程在 wait() 方法中等待通知。
原因:调用 Waiting.class.wait() 进入等待状态,没有其他线程调用 notify 或 notifyAll 方法。
3. BlockedThread-1 (#22)
"BlockedThread-1" #22 prio=5 os_prio=0 tid=0x000002535c417800 nid=0x9c98 waiting on condition [0x000000cd0c5ff000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at Blocked.run(ReadStackLog.java:49)
at java.lang.Thread.run(Thread.java:750)
状态:TIMED_WAITING,表示线程在 sleep 方法中睡眠。
原因:BlockedThread-1 获得了 Blocked.class 的锁后,进入睡眠状态。
4. BlockedThread-2 (#23)
"BlockedThread-2" #23 prio=5 os_prio=0 tid=0x000002535c418000 nid=0xb1dc waiting for monitor entry [0x000000cd0c6ff000]
java.lang.Thread.State: BLOCKED (on object monitor)
at Blocked.run(ReadStackLog.java:49)
at java.lang.Thread.run(Thread.java:750)
状态:BLOCKED,表示线程在等待获取锁。
原因:BlockedThread-2 尝试获取 Blocked.class 的锁,但 Blocked.class 已被 BlockedThread-1 持有,因此进入阻塞状态。
其他线程分析
除了用户自定义的四个线程外,还有一些 JVM 内部线程,如:
- C1 CompilerThreadX 和 C2 CompilerThreadX:JIT 编译器线程,用于即时编译 Java 字节码。
- Finalizer:负责对象终结(垃圾回收前的清理)。
- Reference Handler:处理
Reference对象(如WeakReference)。 - VM Thread:虚拟机线程,负责 JVM 的内部操作。
- Service Thread:服务线程,负责 JVM 的一些后台服务。
- Monitor Ctrl-Break、Attach Listener 等:JVM 的控制和监听线程。
这些线程一般都处于 RUNNABLE 状态,表示它们正在运行或等待运行。
线程状态汇总
- RUNNABLE:线程正在运行或准备运行。
- WAITING:线程在等待某个条件(如
wait、join、LockSupport.park)。 - TIMED_WAITING:线程在等待某个条件或时间(如
sleep、wait带超时)。 - BLOCKED:线程尝试获取一个锁,但被其他线程持有,无法继续执行。
4. 总体总结
你编写的 Java 程序通过启动多个线程,分别模拟了不同的线程状态:
TimeWaitingThread:进入睡眠状态,展示了TIMED_WAITING。WaitingThread:进入等待状态,展示了WAITING。BlockedThread-1和BlockedThread-2:BlockedThread-1获得锁后进入睡眠状态,展示了TIMED_WAITING。BlockedThread-2因为锁被占用而进入阻塞状态,展示了BLOCKED。
通过使用 jps 和 jstack 工具,你可以观察到这些线程的具体状态及其调用堆栈。这对于理解 Java 线程状态和调试多线程应用非常有帮助。
如果你希望进一步探索,可以尝试以下操作:
- 释放锁:在
BlockedThread-1中添加代码在某个条件下释放锁(如不再进入睡眠),观察BlockedThread-2状态如何变化。 - 通知等待线程:在
ReadStackLog的主线程或其他线程中调用Waiting.class.notify(),观察WaitingThread是否从WAITING状态转为RUNNABLE。 - 增加更多线程:模拟更多复杂的线程交互,深入理解多线程编程中的各种状态和问题。
Waiting & Time Waiting
在 Java 中,WAITING 和 TIMED_WAITING 是两种不同的线程状态,它们的区别主要体现在线程等待的条件和等待的时间上。以下是对这两种状态的详细解释:
1. WAITING
- 含义:线程处于无限期等待状态,直到其他线程显式唤醒它。
- 触发条件:
- 调用
Object.wait()方法(不带超时参数)。 - 调用
LockSupport.park()方法。
- 调用
- 特点:
- 线程会一直等待,直到其他线程调用
Object.notify()或Object.notifyAll()来唤醒它。 - 如果没有其他线程唤醒它,线程会一直处于
WAITING状态。
- 线程会一直等待,直到其他线程调用
- 示例:
"WaitingThread" #21 prio=5 os_prio=0 tid=0x000002535c40e800 nid=0xb420 in Object.wait() [0x000000cd0c4ff000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at Waiting.run(ReadStackLog.java:34)
at java.lang.Thread.run(Thread.java:750)
- `WaitingThread` 调用了 `Object.wait()`,正在等待 `Waiting.class` 的锁。
- 该线程需要其他线程调用 `Object.notify()` 或 `Object.notifyAll()` 来唤醒它。
2. TIMED_WAITING
- 含义:线程处于有限期等待状态,等待一段时间后会自动唤醒。
- 触发条件:
- 调用
Thread.sleep(long millis)方法。 - 调用
Object.wait(long timeout)方法(带超时参数)。 - 调用
LockSupport.parkNanos(long nanos)或LockSupport.parkUntil(long deadline)方法。
- 调用
- 特点:
- 线程会等待指定的时间,时间到达后会自动唤醒。
- 如果在等待期间被其他线程唤醒,线程也会提前结束等待。
- 示例:
"TimeWaitingThread" #20 prio=5 os_prio=0 tid=0x000002535c3fb000 nid=0xaaf0 waiting on condition [0x000000cd0c3ff000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at TimeWaiting.run(ReadStackLog.java:20)
at java.lang.Thread.run(Thread.java:750)
- `TimeWaitingThread` 调用了 `Thread.sleep()`,处于睡眠状态。
- 该线程会在指定的睡眠时间(例如 1000000 毫秒)后自动唤醒。
3. 区别对比
| 特性 | WAITING | TIMED_WAITING |
|---|---|---|
| 等待时间 | 无限期等待,直到被唤醒。 | 有限期等待,时间到达后自动唤醒。 |
| 触发方法 | Object.wait()、LockSupport.park() | Thread.sleep()、Object.wait(long)、LockSupport.parkNanos() |
| 是否需要唤醒 | 需要其他线程显式唤醒(notify())。 | 不需要显式唤醒,时间到达后自动唤醒。 |
| 典型场景 | 线程等待某个条件(如生产者-消费者模型)。 | 线程需要暂停一段时间(如定时任务)。 |
4. 代码示例
以下是一个简单的代码示例,展示 WAITING 和 TIMED_WAITING 的区别:
public class WaitingExample {
public static void main(String[] args) {
Object lock = new Object();
// WAITING 示例
Thread waitingThread = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("WaitingThread 进入 WAITING 状态");
lock.wait(); // 无限期等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
waitingThread.start();
// TIMED_WAITING 示例
Thread timedWaitingThread = new Thread(() -> {
try {
System.out.println("TimeWaitingThread 进入 TIMED_WAITING 状态");
Thread.sleep(5000); // 有限期等待 5 秒
} catch (InterruptedException e) {
e.printStackTrace();
}
});
timedWaitingThread.start();
}
}
- 输出:
WaitingThread 进入 WAITING 状态
TimeWaitingThread 进入 TIMED_WAITING 状态
- 分析:
waitingThread调用了lock.wait(),进入WAITING状态,需要其他线程调用lock.notify()来唤醒它。timedWaitingThread调用了Thread.sleep(5000),进入TIMED_WAITING状态,5 秒后会自动唤醒。
5. 总结
WAITING:线程无限期等待,直到被其他线程显式唤醒。TIMED_WAITING:线程有限期等待,时间到达后自动唤醒。- 两者的主要区别在于等待的时间是否有限,以及是否需要显式唤醒。

被折叠的 条评论
为什么被折叠?



