[java 虛擬線程 ]
package com.hugh.java17.v19;
import java.time.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VirtualThrd {
private static final Logger logger = LoggerFactory.getLogger(VirtualThrd.class);
public static void main(String[] args) {
// ExcutorService實現了AutoCloseable接口,可以自動關閉
try (
// 沒使用虛擬線程 壓根走不到最后
// ExecutorService executor = Executors.newCachedThreadPool()
// 使用虛擬線程 可以
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()
) {
IntStream.range(0, 1000000).forEach(
i -> {
executor.submit(() -> {
try {
// 模擬
Thread.sleep(Duration.ofSeconds(1));
System.out.println("執行任務:" + i);
} catch (InterruptedException e) {
// e.printStackTrace();
logger.error("Error: {} - {}", e.getClass().getSimpleName(), e.getMessage());
}
});
}
);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
核心在于:虛擬線程對 synchronized 和 ReentrantLock 的“阻塞處理機制不同”,這與它們的實現方式密切相關,并非“同一級別”的阻塞行為。
關鍵區別:阻塞是否會“卡住攜帶器(平臺線程)”
虛擬線程的設計目標是:在阻塞時“釋放平臺線程”(解除掛載),讓平臺線程去運行其他虛擬線程,從而提高吞吐量。但這個機制只對“協作式阻塞”有效,對“非協作式阻塞”無效。
-
synchronized的問題:非協作式阻塞,會卡住攜帶器
synchronized是 JVM 內置的同步機制,其阻塞邏輯由 JVM 底層實現(依賴操作系統的管程/互斥鎖)。當虛擬線程執行synchronized代碼塊并阻塞時(比如等待鎖),JVM 無法“感知”到這種阻塞是來自虛擬線程,會直接將整個平臺線程(攜帶器)掛起。
→ 結果:平臺線程被卡住,無法去運行其他虛擬線程,虛擬線程的“輕量”優勢失效。 -
ReentrantLock的優勢:協作式阻塞,釋放攜帶器
ReentrantLock是 Java 代碼層面實現的鎖(基于AbstractQueuedSynchronizer框架),其阻塞邏輯(如lock()方法)會通過LockSupport.park()實現。虛擬線程的調度器能識別這種“協作式阻塞”,在虛擬線程阻塞時,會自動將其從平臺線程上“解除掛載”,釋放平臺線程去執行其他任務。
→ 結果:平臺線程不被卡住,繼續高效復用,符合虛擬線程的設計初衷。
為什么兩者“級別不同”?
synchronized是 JVM 底層實現,阻塞時直接關聯操作系統線程狀態,虛擬線程無法干預(非協作)。ReentrantLock是 Java 代碼層面的實現,阻塞時通過 JDK 提供的工具(如LockSupport)通知調度器,虛擬線程可以主動釋放平臺線程(協作)。
這就是為什么在虛擬線程中,推薦用 ReentrantLock 替代 synchronized:前者不會阻塞平臺線程,后者會。
總結
在虛擬線程中,synchronized 和 ReentrantLock 的核心區別不是“是否阻塞”,而是阻塞時是否會導致平臺線程(攜帶器)被卡住:
synchronized會卡住平臺線程 → 降低虛擬線程吞吐量;ReentrantLock不會卡住平臺線程 → 保持虛擬線程的輕量優勢。
這也是 Java 官方在虛擬線程文檔中特別建議用 ReentrantLock 替代 synchronized 的原因。
理解
也就是說 都會阻塞 平臺線程,但是 synchronized 只會呆住,reentrantLock 會處理一下 虛擬線程連接之類,使得 阻塞 解決 是吧
可以這么理解,但更準確的邏輯是:
synchronized阻塞時:會直接讓平臺線程(攜帶器)徹底卡住,既不能繼續執行當前虛擬線程,也不能被調度去執行其他虛擬線程,相當于“浪費”了平臺線程資源。ReentrantLock阻塞時:虛擬線程的調度器會主動把這個虛擬線程從平臺線程上“摘下來”(解除掛載),讓平臺線程可以去執行其他虛擬線程,等阻塞結束后再把這個虛擬線程“掛回去”(重新掛載)。
所以兩者的本質區別是:synchronized 會讓平臺線程“呆死”,而 ReentrantLock 能讓平臺線程“靈活復用”——這也是虛擬線程能實現高吞吐量的關鍵設計之一。



浙公網安備 33010602011771號