Я наткнулся на проблему с виртуальными потоками и ConcurrentHashMap.
Как показано в приведенном ниже коде, если вы введете блокировку в ComputeIfAbsent, VT может не проснуться, всегда. Это действительно зависит от того, как VT запланировано в потоках несущей, но я могу легко это воспроизвести.
Я знаю, что ConcurrentHashMap использует синхронизацию, и VT работает не очень хорошо. с синхронизированным, но нигде не сказано, что следует избегать ConcurrentHashMap, так как это будет весьма разочаровывающим.
class Scratch {
public static void main(String[] args) throws InterruptedException {
var lock = new ReentrantLock();
var map = new ConcurrentHashMap();
var callables = new ArrayList();
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");
}
}
Подробнее здесь: https://stackoverflow.com/questions/778 ... enthashmap