这个问题很有趣:这个程序使用 Java平台线程完成,但使用虚拟线程时却死锁。原因是虚拟线程被钉在同步块中(即不释放其载体),因此没有载体可用。
import java.util.concurrent.CountDownLatch; import java.util.concurrent.locks.ReentrantLock;
public class Main { private static final ReentrantLock lockA = new ReentrantLock(); private static final ReentrantLock lockB = new ReentrantLock();
private static final int CPUs = Runtime.getRuntime().availableProcessors(); private static final CountDownLatch latch = new CountDownLatch(CPUs);
public static void main(String[] args) throws Exception { lockA.lock();
// VT 1 Thread.startVirtualThread(() -> { lockB.lock(); lockA.lock(); lockA.unlock(); lockB.unlock(); }); Thread.sleep(1000);
System.out.println("Starting pinned virtual threads");
// VT 2..CPUs+1 for (int i = 0; i < CPUs; i++) { Thread.startVirtualThread(() -> { synchronized (Main.class) { lockB.lock(); lockB.unlock(); latch.countDown(); System.out.println("Exiting synchronized block"); } }); }
// This should unblock VT1, which unblocks VT2..CPUs+1 // Instead we deadlock, since VT1 can't execute as there are no // available platform threads. lockA.unlock(); latch.await(); } }
|
这一点并不广为人知,但你永远都不应该使用同步。同步
关键字是一把锤子,人们对它的理解很差,更糟糕的是,它在 JVM 中的实现也很差。内核中存在大量替代方案是有原因的。JEP 425 中明确提到了这一点。