Virtual threads created more platform threads

Jianbin Chen jianbin at apache.org
Wed Jul 2 05:50:27 UTC 2025


Hi Liang,

Thank you and everyone for your patient answers. I verified this with JDK
24, and the same example did not show platform thread growth. However,
there's one thing I don't understand: why are these threads never
reclaimed? Most of them are in a waiting state - isn't this a waste of
resources? Sometimes it increases by hundreds of threads. Is there any way
to suppress this behavior on JDK 21?

Best Regards.
Jianbin Chen, github-id: funky-eyes

Chen Liang <liangchenblue at gmail.com> 于 2025年7月2日周三 12:58写道:

> Hello Jianbin, please provide a test case that can reproduce this issue on
> 24. 21 is not supported by active JDK development.
>
> On Tue, Jul 1, 2025, 23:52 Jianbin Chen <jianbin at apache.org> wrote:
>
>> Hi everyone,
>> thank you for your replies and assistance. So this issue occurring in JDK
>> 21 is considered normal behavior, correct? However, I've observed that
>> these expanded threads are not being garbage collected - they remain in a
>> waiting state for several minutes without disappearing. Sometimes they can
>> expand to several hundred threads, and these threads, once created, remain
>> unused, continuously wasting thread resources. Therefore, I'm attaching a
>> local reproduction example of this issue to ensure the information in this
>> email is complete.
>> -Djava.util.concurrent.ForkJoinPool.common.parallelism=1
>> `
>> The following example clearly shows the forkjoinpool expanding. I have
>> also recorded the runtime stack trace for this and submitted it as an
>> attachment.
>>
>> ```
>>     public static void main(String[] args) throws InterruptedException {
>>         Executor executor =
>> ThreadPoolFactory.newVirtualThreadPerTaskExecutor();
>>         String a = "a";
>>         executor.execute(() -> {
>>             synchronized (a) {
>>             try {
>>             a.wait();
>>             } catch (InterruptedException e) {
>>             throw new RuntimeException(e);
>>             }
>>             }
>>         });
>>         executor.execute(() -> {
>>             synchronized (a) {
>>             try {
>>             a.wait();
>>             } catch (InterruptedException e) {
>>             throw new RuntimeException(e);
>>             }
>>             }
>>         });
>>         Thread.sleep(120000);
>>     }
>> ```
>> After switching to using condition, it can be clearly observed through
>> jstack that the forkjoinpool did not expand as many threads, but 3 threads
>> still appeared, which might be related to incorrect usage of my JVM
>> parameters.
>>
>> ```
>>  public static void main(String[] args) throws InterruptedException {
>>         Executor executor =
>> ThreadPoolFactory.newVirtualThreadPerTaskExecutor();
>>         List<ReentrantLock> list = new ArrayList<>();
>>         list.add(new ReentrantLock());
>>         list.add(new ReentrantLock());
>>         list.add(new ReentrantLock());
>>         list.add(new ReentrantLock());
>>         list.add(new ReentrantLock());
>>         list.add(new ReentrantLock());
>>         for (int i = 0; i < list.size(); i++) {
>>             ReentrantLock value = list.get(i);
>>        Condition condition = value.newCondition();
>>             executor.execute(() -> {
>>                 value.lock();
>>                     try {
>>                         condition.await();
>>                     } catch (InterruptedException e) {
>>                         throw new RuntimeException(e);
>>                     }finally {
>>                         value.unlock();
>>                     }
>>             });
>>         }
>>         Thread.sleep(120000);
>>     }
>> ```
>>
>> Best Regards.
>> Jianbin Chen, github-id: funky-eyes
>>
>> Peter Eastham <petereastham at gmail.com> 于 2025年7月2日周三 12:16写道:
>>
>>> I hope to not create noise with my own comments, and I will concur with
>>> you that JEP 491 should mean this is resolved in Java 24, which Jianbin
>>> Chen should try out before and then alongside Robert's recommendation for
>>> creating a very simple reproduction.
>>>
>>> As Java 21 is still the current LTS, it isn't completely unreasonable to
>>> forward concerns to the mailing list. My understanding in this particular
>>> case is that JEP 491 is not going to be back ported to Java 21 as it has a
>>> dependency from a change in Java 23. (Potentially more, I can't remember
>>> the conversation completely, I only skimmed that email chain)
>>>
>>>
>>> Thanks,
>>> - Peter
>>>
>>> P.S. As I do a similar job, I'd like to call out that Vendors letting
>>> the occasional support question slip into here is a fine price to pay for
>>> the amount of questions they handle instead.
>>>
>>>
>>>
>>> On Tue, Jul 1, 2025, 9:17 PM Chen Liang <liangchenblue at gmail.com> wrote:
>>>
>>>> Hello, I don't think this would happen for JDK 24 - JEP 491 removed the
>>>> code that calls Blocker in Object.wait, which is exactly the goal of that
>>>> JEP.
>>>>
>>>> Note that virtual threads are still pinned when call stack goes into
>>>> native, as native execution may pass address to stack variables that will
>>>> be lost in context switches. In these cases, the traditional managed block
>>>> happens again.
>>>>
>>>> P.S. I personally think it is somewhat not responsible for JDK vendors
>>>> to ask users to upstream a question for an older JDK release that might no
>>>> longer apply on the latest release to a development-oriented mailing list.
>>>>
>>>> On Tue, Jul 1, 2025 at 9:47 PM Jianbin Chen <jianbin at apache.org> wrote:
>>>>
>>>>>
>>>>> Hi Loom-dev Community,
>>>>>
>>>>> I have a question about platform thread creation triggered by calling
>>>>> future.get() within virtual threads, and I would like to ask the community
>>>>> for assistance. The detailed information can be found in this issue:
>>>>> https://github.com/adoptium/adoptium-support/issues/1319. I hope to
>>>>> receive some help from the community regarding this matter. Thank you.
>>>>> Additionally, I'd like to know if this situation will still occur in
>>>>> JDK 24 and above?
>>>>>
>>>>> Best Regards.
>>>>> Jianbin Chen, github-id: funky-eyes
>>>>>
>>>>>
>>>>> Best Regards.
>>>>> Jianbin Chen, github-id: funky-eyes
>>>>>
>>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/loom-dev/attachments/20250702/1ae7fac4/attachment.htm>


More information about the loom-dev mailing list