Java虚拟线程(Virtual Threads)与ConcurrentHashMap的唤醒异常问题
Java虚拟线程与ConcurrentHashMap的死锁问题
在使用Java虚拟线程(VT)结合ConcurrentHashMap时,遇到了异常问题:当在computeIfAbsent方法内部获取锁时,虚拟线程可能永远无法被唤醒。该问题的出现与虚拟线程在载体线程上的调度方式相关,且可轻松复现此场景。
我知道ConcurrentHashMap内部使用synchronized关键字,而虚拟线程与synchronized的兼容性不佳,但官方并未提及需避免使用ConcurrentHashMap,这一点令人遗憾。
复现代码
class Scratch { public static void main(String[] args) throws InterruptedException { var lock = new ReentrantLock(); var map = new ConcurrentHashMap<Integer, String>(); var callables = new ArrayList<Callable<Void>>(); for (int i = 0; i < 32 /* more than threads in FJ pool */; i++) { callables.add(() -> { System.out.println("Spawned thread " + Thread.currentThread().threadId()); map.computeIfAbsent(1, k -> { System.out.println("on lock() " + Thread.currentThread().threadId()); lock.lock(); try { System.out.println("within lock() " + Thread.currentThread().threadId()); } finally { lock.unlock(); } return ""; }); System.out.println("Exiting " + Thread.currentThread().threadId()); return null; }); } new Thread(() -> { System.out.println("locking " + Thread.currentThread().threadId()); lock.lock(); try { Thread.sleep(2000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("unlocking " + Thread.currentThread().threadId()); lock.unlock(); System.out.println("unlocked " + Thread.currentThread().threadId()); }).start(); while (!lock.isLocked()) { Thread.sleep(10); } // it works with Executors.newCachedThreadPool() try (var es = Executors.newVirtualThreadPerTaskExecutor()) { es.invokeAll(callables); } System.out.println("done"); } }
内容的提问来源于stack exchange,提问作者milan
相关产品推荐
相关产品推荐

