<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=big5">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Hi Ben,<br>
<br>
Thanks for raising these questions¡Xgetting feedback is crucial in the Preview stage of features.<br>
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
I wrote a reply to the Reddit thread so I'll just summarize here:</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
It is important to note that <i>mapConcurrent()</i> is not a part of the Structured Concurrency JEPs, so it is not designed to join SC scopes.</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
I'm currently experimenting with ignoring-but-restoring interrupts on the "calling thread" for
<i>mapConcurrent()</i>, as well as capping work-in-progress to <i>maxConcurrency</i> (not only capping the concurrency but also the amount of completed-but-yet-to-be-pushed work). Both of these adjustments should increase predictability of behavior in the face
of blocking operations with variable delays.</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Another adjustment I'm looking at right now is to harden/improve the cleanup to wait for concurrent tasks to acknowledge cancellation, so that once the finisher is done executing the VTs are known to have terminated.</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
As for not preserving the encounter order, that would be a completely different thing, and I'd encourage you to experiment with that if that functionality would be interesting for your use-case(s).</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Again, thanks for your feedback!</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div id="Signature" class="elementToProof" style="color: inherit;">
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Cheers,<br>
¡Ô</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<b><br>
</b></div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<b>Viktor Klang</b></div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Software Architect, Java Platform Group<br>
Oracle</div>
</div>
<div id="appendonsend"></div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> core-libs-dev <core-libs-dev-retn@openjdk.org> on behalf of Jige Yu <yujige@gmail.com><br>
<b>Sent:</b> Friday, 3 January 2025 17:53<br>
<b>To:</b> core-libs-dev@openjdk.org <core-libs-dev@openjdk.org><br>
<b>Subject:</b> mapConcurrent() with InterruptedException</font>
<div> </div>
</div>
<div>
<div dir="ltr">Hi Java Experts,
<div><br>
</div>
<div>I sent this email incorrectly to loom-dev@ and was told on Reddit that core-libs-dev is the right list.</div>
<div><br>
</div>
<div>The question is about the behavior of mapConcurrent() when the thread is interrupted.</div>
<div><br>
</div>
<div>Currently mapConcurrent()'s finisher phase will re-interrupt the thread, then stop at whatever element that has already been processed and return.</div>
<div><br>
</div>
<div>This strikes me as a surprising behavior, because for example if I'm running:</div>
<div><br>
</div>
<div> Stream.of(1, 2, 3)</div>
<div> .gather(mapConcurrent(i -> i * 2))</div>
<div> .toList()</div>
<div><br>
</div>
<div>and the thread is being interrupted, the result could be any of [2], [2, 4] or [2, 4, 6].</div>
<div><br>
</div>
<div>Since thread interruption is cooperative, there is no guarantee that the thread being interrupted will just abort. It's quite possible that it'll keep going and then will use for example [2] as the result of doubling the list of [1, 2, 3], which is imho
incorrect.</div>
<div><br>
</div>
<div>In the <a href="https://www.reddit.com/r/java/comments/1hr8xyu/observations_of_gatherersmapconcurrent/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button">
Reddit</a> thread, someone argued that interruption rarely happens so it's more of a theoretical issue. But interruption can easily happen in Structured Concurrency or in mapConcurrent() itself if any subtask has failed in order to cancel/interrupt the other
ongoing tasks.</div>
<div><br>
</div>
<div>There had been discussion about alternative strategies:</div>
<div>
<ol>
<li>Don't respond to interruption and just keep running to completion.</li><li>Re-interrupt thread and wrap the InterruptedException in a standard unchecked exception (StructuredConcurrencyInterruptedException?).</li></ol>
<div><br>
</div>
</div>
<div>I have concerns with option 1 because it disables cancellation propagation when mapConcurrent() itself is used in a subtask of a parent mapConcurrent() or in a StructuredConcurrencyScope.</div>
<div><br>
</div>
<div>Both equivalent Future-composition async code, or C++'s fiber trees support cancellation propagation and imho it's a critical feature or else it's possible that a zombie thread is still sending RPCs long after the main thread has exited (failed, or falled
back to some default action).</div>
<div><br>
</div>
<div>My arguments for option 2:</div>
<div>
<ol>
<li>InterruptedException is more error prone than traditional checked exceptions for
<b>users</b> to catch and handle. They can forget to re-interrupt the thread. It's so confusing that even seasoned programmers may not know they are
<b>supposed to</b> re-interrupt the thread.</li><li>With Stream API using functional interfaces like Supplier, Function, the option of just tacking on "throws IE" isn't available to many users.</li><li>With Virtual Threads, it will be more acceptable, or even become common to do blocking calls from a stream operation (including but exclusive to mapConcurrent()). So the chance users are forced to deal with IE will become substantially higher.</li><li>Other APIs such as the Structured Concurrency API have already started wrapping system checked exceptions like ExecutionException, TimeoutException in unchecked exceptions ( <a class="x_gmail-relative x_gmail-pointer-events-auto x_gmail-a x_gmail-cursor-pointer x_gmail-underline" href="https://download.java.net/java/early_access/loom/docs/api/java.base/java/util/concurrent/StructuredTaskScope.html#join()" rel="noopener nofollow ugc" target="_blank" style="font-size:14px; margin-top:0px; font-family:-apple-system,"system-ui","Segoe UI",Roboto,"Helvetica Neue",Arial,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol",sans-serif">join()</a> for
example).</li><li>Imho, exceptions that we'd rather users not catch and handle but instead should mostly just propagate up as is, should be unchecked.</li></ol>
<div>There is also a <a href="https://www.reddit.com/r/java/comments/1hr8xyu/comment/m4z4f8c/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button">
side discussion</a> about whether mapConcurrent() is better off preserving input order or push to downstream as soon as an element is computed. I'd love to discuss that topic too but maybe it's better to start a separate thread?</div>
</div>
<div><br>
</div>
<div>Thank you and cheers!</div>
<div><br>
</div>
<div>Ben Yu</div>
<div><br>
</div>
</div>
</div>
</body>
</html>