虚拟线程对 synchronized、ReentrantLock 这类 “锁”,并没有做特殊 “自动优化”,反而会有坑。
只有一类特殊情况:阻塞在 java.util.concurrent.locks 的 park 等待时,虚拟线程才会像 IO 阻塞一样,让出平台线程。
下面用 Java 开发最容易遇到的场景,讲清楚虚拟线程 + 锁到底怎么回事。
虚拟线程只有在遇到 JVM 能识别的 “挂载点” 时,才会释放底层平台线程:
sleep()LockSupport.park()(AQS 底层)Object.wait()这些都会触发:虚拟线程挂起 → 平台线程释放。
这是最重要的坑。
synchronized (lock) {
// 临界区
}
虚拟线程进入 synchronized 阻塞时:
原因:synchronized 是 JVM 内部的 monitor 锁,目前 OpenJDK 还没有把它改造为 “虚拟线程友好” 的挂起机制。
一句话:synchronized 在虚拟线程下,仍然是重量级阻塞,不释放平台线程。
java.util.concurrent.locks` 包下的锁,底层是:`LockSupport.park()` / `unpark()
这是 JVM 明确识别的挂载点。
private final ReentrantLock lock = new ReentrantLock();
public void func() {
lock.lock(); // 竞争不到锁时 → park()
try {
// ...
} finally {
lock.unlock();
}
}
虚拟线程竞争不到锁时:
LockSupport.park()这就是虚拟线程对锁的唯一真实优化。
synchronized (obj) {
obj.wait(); // 会 park → 虚拟线程挂起,释放平台线程
}
wait() 会让虚拟线程挂起并让出平台线程,没问题。但再次强调:抢锁那一步的 synchronized 本身不优化。
| 锁方式 | 虚拟线程阻塞时是否释放平台线程 | 虚拟线程友好度 |
|---|---|---|
| synchronized | 不释放 | ❌ 不友好 |
| ReentrantLock | 释放 | ✅ 友好 |
| ReentrantReadWriteLock | 释放 | ✅ 友好 |
| Object.wait() | 释放 | ✅ 友好 |
| sleep() | 释放 | ✅ 友好 |
在 Spring Boot 3.2+ 开启虚拟线程后:
这就是虚拟线程对 “锁” 的全部真实行为。