Question about mapConcurrent() Behavior and Happens-Before Guarantees
Viktor Klang
viktor.klang at oracle.com
Mon Jul 7 09:34:57 UTC 2025
Hi Jige,
>Initially, I thought this design choice might provide a strong happens-before guarantee. My assumption was that an application catching a RuntimeException would be able to observe all side effects from the virtual threads, even though this practice is generally discouraged. This seemed like a potentially significant advantage, outweighing the risk of a virtual thread failing to respond to interruption or responding slowly.
Unless explicitly stated in the API contract, no such guarantees should be presumed to exist.
As for general resource-management in Stream, I have contemplated designs for Gatherer (and Collector) to be able to participate in the onClose actions, but there's a lot of ground to cover to ensure correct ordering and sufficiently-encompassing of cleanup action execution.
Cheers,
√
Viktor Klang
Software Architect, Java Platform Group
Oracle
________________________________
From: core-libs-dev <core-libs-dev-retn at openjdk.org> on behalf of Jige Yu <yujige at gmail.com>
Sent: Thursday, 3 July 2025 16:36
To: core-libs-dev at openjdk.org <core-libs-dev at openjdk.org>
Subject: Question about mapConcurrent() Behavior and Happens-Before Guarantees
Hi JDK Core Devs,
I'm writing to you today with a question about the behavior of mapConcurrent() and its interaction with unchecked exceptions. I've been experimenting with the API and observed that mapConcurrent() blocks and joins all virtual threads upon an unchecked exception before propagating it.
Initially, I thought this design choice might provide a strong happens-before guarantee. My assumption was that an application catching a RuntimeException would be able to observe all side effects from the virtual threads, even though this practice is generally discouraged. This seemed like a potentially significant advantage, outweighing the risk of a virtual thread failing to respond to interruption or responding slowly.
However, I've since realized that mapConcurrent() cannot fully guarantee a strong happens-before relationship when an unchecked exception occurs somewhere in the stream pipeline. While it can block and wait for exceptions thrown by the mapper function or downstream operations, it appears unable to intercept unchecked exceptions thrown by an upstream source.
Consider a scenario with two input elements: if the first element starts a virtual thread, and then the second element causes an unchecked exception from the upstream before reaching the gather() call, the virtual thread initiated by the first element would not be interrupted. This makes the "happens-before" guarantee quite nuanced in practice.
This brings me to my core questions:
1. Is providing a happens-before guarantee upon an unchecked exception a design goal for mapConcurrent()?
2. If not, would it be more desirable to not join on virtual threads when unchecked exceptions occur? This would allow the application code to catch the exception sooner and avoid the risk of being blocked indefinitely.
Thank you for your time and insights.
Best regards,
Ben Yu
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20250707/dcc3130a/attachment-0001.htm>
More information about the core-libs-dev
mailing list