Question

Java virtual threads (Project Loom) deadlock when used with synchronized blocks

b312fbcb-b342-443d-ad18-ce9b8fbf539e

After migrating a Spring Boot 3.2 app to virtual threads via spring.threads.virtual.enabled=true, we're seeing deadlocks under load. Thread dumps show virtual threads pinned to carrier threads inside synchronized blocks:

VirtualThread[#42]/runnable@ForkJoinPool-1-worker-3 - parking to wait for monitor
    at com.example.LegacyDao.query(LegacyDao.java:45) <== synchronized method

The same code worked fine with platform threads. Is it true that synchronized pins virtual threads to carrier threads? Should all synchronized be replaced with ReentrantLock? What about third-party libraries that use synchronized internally (JDBC drivers, connection pools)?