JDK-8339459 : A virtualThread is blocked forever in synchronized block
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 21,22,23,24
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_10
  • CPU: x86_64
  • Submitted: 2024-09-03
  • Updated: 2024-09-06
Related Reports
Relates :  
Description
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



Comments
Additional information from the submitter: In the recent jdk-24-loom, this issue doesn't happen. But this bug also exists in jdk-22/23/24. This test passed in openjdk-24-loom+5-48_windows-x64 and openjdk-24-loom+7-60_windows-x64.
06-09-2024

Informed the submitter to test the loom EA builds and a link to the draft JEP.
05-09-2024

[~tongwan] Did you reply to the submitter asking them to test the loom EA builds and a link to the draft JEP?
04-09-2024

The observations on Windows 11: JDK 21.0.5+7: All tests passed.
03-09-2024

JDK-8337395 is the current draft of the JEP to address the pinning issues with object monitors. There are EA builds at https://jdk.java.net/loom/ with the changes. We are looking for as many projects to test the changes.
03-09-2024