ADDITIONAL SYSTEM INFORMATION :
Windows 10 x64 / Java 21.0.4
A DESCRIPTION OF THE PROBLEM :
A virtualThread can't enter a monitor forever when no virtual thread owns the monitor in synchronized block except setting the system property -Djdk.virtualThreadScheduler.maxPoolSize=1. And it's ok in the platformThread case.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test
>%java21_home%\bin\java VtBlockedForeverInSyncBlockTest
[pt-lock-2#22] Worker#2 starts.
[pt-lock-0#20] Worker#0 starts.
[pt-lock-1#21] Worker#1 starts.
[pt-lock-3#23] Worker#3 starts.
[pt-lock-4#24] Worker#4 starts.
[pt-lock-6#26] Worker#6 starts.
[pt-lock-7#27] Worker#7 starts.
[pt-lock-5#25] Worker#5 starts.
[pt-lock-8#28] Worker#8 starts.
[pt-lock-9#29] Worker#9 starts.
[pt-lock-2#22] Worker#2 sleeping in lock ..
[pt-lock-2#22] Worker#2 ends.
[pt-lock-0#20] Worker#0 sleeping in lock ..
[pt-lock-0#20] Worker#0 ends.
[pt-lock-1#21] Worker#1 sleeping in lock ..
[pt-lock-1#21] Worker#1 ends.
[pt-lock-3#23] Worker#3 sleeping in lock ..
[pt-lock-3#23] Worker#3 ends.
[pt-lock-4#24] Worker#4 sleeping in lock ..
[pt-lock-6#26] Worker#6 sleeping in lock ..
[pt-lock-4#24] Worker#4 ends.
[pt-lock-6#26] Worker#6 ends.
[pt-lock-7#27] Worker#7 sleeping in lock ..
[pt-lock-5#25] Worker#5 sleeping in lock ..
[pt-lock-7#27] Worker#7 ends.
[pt-lock-8#28] Worker#8 sleeping in lock ..
[pt-lock-5#25] Worker#5 ends.
[pt-lock-8#28] Worker#8 ends.
[pt-lock-9#29] Worker#9 sleeping in lock ..
[pt-lock-9#29] Worker#9 ends.
[pt-sync-1#31] Worker#1 starts.
[pt-sync-0#30] Worker#0 starts.
[pt-sync-3#33] Worker#3 starts.
[pt-sync-5#35] Worker#5 starts.
[pt-sync-2#32] Worker#2 starts.
[pt-sync-6#36] Worker#6 starts.
[pt-sync-7#37] Worker#7 starts.
[pt-sync-4#34] Worker#4 starts.
[pt-sync-1#31] Worker#1 sleeping in sync ..
[pt-sync-8#38] Worker#8 starts.
[pt-sync-9#39] Worker#9 starts.
[pt-sync-1#31] Worker#1 ends.
[pt-sync-9#39] Worker#9 sleeping in sync ..
[pt-sync-8#38] Worker#8 sleeping in sync ..
[pt-sync-9#39] Worker#9 ends.
[pt-sync-8#38] Worker#8 ends.
[pt-sync-4#34] Worker#4 sleeping in sync ..
[pt-sync-4#34] Worker#4 ends.
[pt-sync-7#37] Worker#7 sleeping in sync ..
[pt-sync-6#36] Worker#6 sleeping in sync ..
[pt-sync-7#37] Worker#7 ends.
[pt-sync-2#32] Worker#2 sleeping in sync ..
[pt-sync-6#36] Worker#6 ends.
[pt-sync-2#32] Worker#2 ends.
[pt-sync-5#35] Worker#5 sleeping in sync ..
[pt-sync-3#33] Worker#3 sleeping in sync ..
[pt-sync-5#35] Worker#5 ends.
[pt-sync-3#33] Worker#3 ends.
[pt-sync-0#30] Worker#0 sleeping in sync ..
[pt-sync-0#30] Worker#0 ends.
[main] Platform thread tests pass!
[vt-lock-0#40] Worker#0 starts.
[vt-lock-0#40] Worker#0 sleeping in lock ..
[vt-lock-1#42] Worker#1 starts.
[vt-lock-3#44] Worker#3 starts.
[vt-lock-4#45] Worker#4 starts.
[vt-lock-5#46] Worker#5 starts.
[vt-lock-6#47] Worker#6 starts.
[vt-lock-7#48] Worker#7 starts.
[vt-lock-8#49] Worker#8 starts.
[vt-lock-9#50] Worker#9 starts.
[vt-lock-2#43] Worker#2 starts.
[vt-lock-0#40] Worker#0 ends.
[vt-lock-1#42] Worker#1 sleeping in lock ..
[vt-lock-1#42] Worker#1 ends.
[vt-lock-3#44] Worker#3 sleeping in lock ..
[vt-lock-4#45] Worker#4 sleeping in lock ..
[vt-lock-3#44] Worker#3 ends.
[vt-lock-4#45] Worker#4 ends.
[vt-lock-5#46] Worker#5 sleeping in lock ..
[vt-lock-5#46] Worker#5 ends.
[vt-lock-6#47] Worker#6 sleeping in lock ..
[vt-lock-6#47] Worker#6 ends.
[vt-lock-7#48] Worker#7 sleeping in lock ..
[vt-lock-7#48] Worker#7 ends.
[vt-lock-8#49] Worker#8 sleeping in lock ..
[vt-lock-8#49] Worker#8 ends.
[vt-lock-9#50] Worker#9 sleeping in lock ..
[vt-lock-9#50] Worker#9 ends.
[vt-lock-2#43] Worker#2 sleeping in lock ..
[vt-lock-2#43] Worker#2 ends.
[vt-sync-0#55] Worker#0 starts.
[vt-sync-0#55] Worker#0 sleeping in sync ..
[vt-sync-2#57] Worker#2 starts.
[vt-sync-1#56] Worker#1 starts.
[vt-sync-3#58] Worker#3 starts.
[vt-sync-3#58] Worker#3 sleeping in sync ..
[vt-sync-4#59] Worker#4 starts.
[vt-sync-1#56] Worker#1 sleeping in sync ..
[vt-sync-5#60] Worker#5 starts.
[vt-sync-1#56] Worker#1 ends.
[vt-sync-6#61] Worker#6 starts. // Here the process hangs forever!
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The java process exits normally.
ACTUAL -
The java process hangs abnormally.
---------- BEGIN SOURCE ----------
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
class VtBlockedForeverInSyncBlockTest {
static final int CONC = Integer.getInteger("conc", 10);
static final long SLEEP = Long.getLong("sleep", 10);
public static void main(String[] args) throws InterruptedException {
var main = Thread.currentThread().getName();
test(true);
System.out.printf("[%s] Platform thread tests pass!%n", main);
test(false);
System.out.printf("[%s] Virtual thread tests pass!%n", main);
System.out.printf("[%s] Test ok!%n", main);
}
static void test(boolean pt) throws InterruptedException {
testLock(pt, CONC);
testSync(pt, CONC);
}
static void testSync(boolean pt, int n) throws InterruptedException {
ExecutorService executor = newExecutor(pt, true);
try {
final Object lock = new Object();
for (var i = 0; i < n; ++i) {
var id = i;
executor.submit(()-> {
var thr = Thread.currentThread().getName();
var tid = Thread.currentThread().threadId();
System.out.printf("[%s#%d] Worker#%s starts.%n", thr, tid, id);
synchronized(lock) { // VTs blocked forever?
try {
System.out.printf("[%s#%d] Worker#%s sleeping in sync ..%n",
thr, tid, id);
if (SLEEP >= 0) Thread.sleep(SLEEP);
} catch (InterruptedException e) {
// Ignore
}
}
System.out.printf("[%s#%d] Worker#%s ends.%n", thr, tid, id);
});
}
} finally {
executor.shutdown();
}
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
}
static void testLock(boolean pt, int n) throws InterruptedException {
ExecutorService executor = newExecutor(pt, false);
try {
Lock lock = new ReentrantLock();
for (var i = 0; i < n; ++i) {
var id = i;
executor.submit(()-> {
var thr = Thread.currentThread().getName();
var tid = Thread.currentThread().threadId();
System.out.printf("[%s#%d] Worker#%s starts.%n", thr, tid, id);
lock.lock();
try {
System.out.printf("[%s#%d] Worker#%s sleeping in lock ..%n",
thr, tid, id);
if (SLEEP >= 0) Thread.sleep(SLEEP);
} catch (InterruptedException e) {
// Ignore
} finally {
lock.unlock();
}
System.out.printf("[%s#%d] Worker#%s ends.%n", thr, tid, id);
});
}
} finally {
executor.shutdown();
}
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
}
static ExecutorService newExecutor(boolean pt, boolean sc) {
var b = sc? "sync-": "lock-";
ThreadFactory tf = pt? Thread.ofPlatform().name("pt-"+ b, 0).factory():
Thread.ofVirtual().name("vt-"+ b, 0).factory();
return Executors.newThreadPerTaskExecutor(tf);
}
}
---------- END SOURCE ----------
FREQUENCY : always