RFR: avoid extra park of vthread when using fixed thread pool [v2]

Alan Bateman alanb at openjdk.java.net
Mon Aug 30 11:42:14 UTC 2021


On Thu, 26 Aug 2021 11:00:58 GMT, Miao Zheng <github.com+20216587+miao-zheng at openjdk.org> wrote:

>> The test case of ParkWithFixedThreadPool.java create 300 virtual threads, each vthread(exclude latest vthread) park itself and unpark previous vthread. The expected result is any vthread can finish.
>> 
>> Running this test case in slowdebug and the test will random hang.
>> 
>> There are three vthreads which are vt-1, vt-2, vt-3;
>> (1) vt-1 take the ReentrantLock, and vt-2 try to unpark vt-1, and vt-2 fail to get ReentrantLock so it park itself( the call stack is shown below); 
>> (2)vt-3 unpark vt-2, and vt-2 try to get ReentrantLock again, but the ReentrantLock is still owned by vt-1, vt-2 park itself again;
>> (3)vt-1 release the ReentrantLock and unpark vt-2, vt-2 park itself at ParkWithFixedThreadPool.java:55, and it will never unpark.(because the unpark from vt-3 has consumed)
>> 
>> The reason is scheduler.execute() will try to alloc a Reentrant lock when using fix thread pool, the call stack is like:
>>     at java.lang.VirtualThread.tryPark(VirtualThread.java:472)
>>     at java.lang.VirtualThread.park(VirtualThread.java:424)
>>     at java.lang.System$2.parkVirtualThread(System.java:1279)
>>     at sun.misc.VirtualThreads.park(VirtualThreads.java:56)
>>     at java.util.concurrent.locks.LockSupport.park(LockSupport.java:183)
>>     at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
>>     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
>>     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
>>     at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
>>     at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
>>     at java.util.concurrent.LinkedBlockingQueue.offer(LinkedBlockingQueue.java:418)
>>     at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1371)
>>     at java.lang.VirtualThread.unpark(VirtualThread.java:502)
>>     at java.lang.System$2.unparkVirtualThread(System.java:1287)
>>     at sun.misc.VirtualThreads.unpark(VirtualThreads.java:70)
>>     at ParkWithFixedThreadPool$1.run(ParkWithFixedThreadPool.java:51)
>> 
>> 
>> The solution is switch back to carrier thread before call scheduler.execute();
>
> Miao Zheng has refreshed the contents of this pull request, and previous commits have been removed. The incremental views will show differences compared to the previous content of the PR.

Marked as reviewed by alanb (Committer).

The CustomScheduler test was indeed failing with this change but it's due to a test issue where it runs the scheduler tasks on the current thread. I've remove that case from the test so I think we are good to go now.

-------------

PR: https://git.openjdk.java.net/loom/pull/59


More information about the loom-dev mailing list