<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<p>I have tried things out over the evolution of Structured
Concurrency, but not this specific case.</p>
<p>While I agree that trying things out is a <b><i>good </i></b>way
to see how it works, trying things out does not confirm actual
architectural or design intent, it merely speculates on intent. It
would be nice for the architects to explicitly specify their
intent in JEPs and elsewhere.</p>
<p>But, thanks for the example... did you write it yourself, or have
GitHub Copilot do it? 😉 Just teasing...<br>
</p>
<div class="moz-cite-prefix">On 2023-10-27 10:16 a.m., Josiah Noel
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:CAJ_t5UaOqKqjEZ=5sDPb24HNjAE+W4i4RnZ1CofcfJqmBhUc2w@mail.gmail.com">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">Have you tried it out? Trying this
stuff out is the best way to see how it works, in
any case, observe the following example </div>
<div dir="ltr">
<div
style="background-color:rgb(28,31,34);padding:0px 0px 0px 2px">
<div
style="color:rgb(199,205,209);font-family:Consolas;white-space:pre"><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(255,0,127)">try</span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(249,250,244)">(</span><span
style="color:rgb(82,227,246);background-color:rgb(65,65,4)">ShutdownOnSuccess</span><span
style="color:rgb(255,0,127)"><</span><span
style="color:rgb(191,164,164)">Integer</span><span
style="color:rgb(255,0,127)">></span><span
style="color:rgb(207,191,173)"> scope </span><span
style="color:rgb(255,0,127)">=</span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(255,0,127)">new</span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(82,227,246);background-color:rgb(65,65,4)">StructuredTaskScope</span><span
style="color:rgb(255,0,127);background-color:rgb(65,65,4)">.</span><span
style="color:rgb(167,236,33);background-color:rgb(65,65,4)">ShutdownOnSuccess</span><span
style="color:rgb(255,0,127)"><></span><span
style="color:rgb(249,250,244)">())</span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(249,250,244)">{</span></p><p
style="margin:0px">
</p><p style="margin:0px"><span style="color:rgb(207,191,173)"> </span><span
style="color:rgb(197,104,28)">var</span><span
style="color:rgb(207,191,173)"> fail </span><span
style="color:rgb(255,0,127)">=</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> scope</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(167,236,33)">fork</span><span
style="color:rgb(249,250,244)">(</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(249,250,244)">()</span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(255,0,127)">-></span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(249,250,244)">{</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(255,0,127)">throw</span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(255,0,127)">new</span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(167,236,33)">IllegalAccessException</span><span
style="color:rgb(249,250,244)">()</span><span
style="color:rgb(255,0,127)">;</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(249,250,244)">})</span><span
style="color:rgb(255,0,127)">;</span></p><p
style="margin:0px">
</p><p style="margin:0px"><span style="color:rgb(207,191,173)"> scope</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(167,236,33)">fork</span><span
style="color:rgb(249,250,244)">(</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(249,250,244)">()</span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(255,0,127)">-></span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(249,250,244)">{</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(82,227,246)">Thread</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(167,236,33)">sleep</span><span
style="color:rgb(249,250,244)">(</span><span
style="color:rgb(82,227,246)">Duration</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(167,236,33)">of</span><span
style="color:rgb(249,250,244)">(</span><span
style="color:rgb(207,191,173)">random</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(167,236,33)">nextInt</span><span
style="color:rgb(249,250,244)">(</span><span
style="color:rgb(196,140,255)">0</span><span
style="color:rgb(255,0,127)">,</span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(196,140,255)">1000</span><span
style="color:rgb(249,250,244)">)</span><span
style="color:rgb(255,0,127)">,</span><span
style="color:rgb(207,191,173)"> ChronoUnit</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(207,191,173)">MILLIS</span><span
style="color:rgb(249,250,244)">))</span><span
style="color:rgb(255,0,127)">;</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(255,0,127)">return</span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(196,140,255)">1</span><span
style="color:rgb(255,0,127)">;</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(249,250,244)">})</span><span
style="color:rgb(255,0,127)">;</span></p><p
style="margin:0px">
</p><p style="margin:0px"><span style="color:rgb(207,191,173)"> scope</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(167,236,33)">fork</span><span
style="color:rgb(249,250,244)">(</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(249,250,244)">()</span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(255,0,127)">-></span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(249,250,244)">{</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(82,227,246)">Thread</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(167,236,33)">sleep</span><span
style="color:rgb(249,250,244)">(</span><span
style="color:rgb(82,227,246)">Duration</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(167,236,33)">of</span><span
style="color:rgb(249,250,244)">(</span><span
style="color:rgb(207,191,173)">random</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(167,236,33)">nextInt</span><span
style="color:rgb(249,250,244)">(</span><span
style="color:rgb(196,140,255)">0</span><span
style="color:rgb(255,0,127)">,</span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(196,140,255)">1000</span><span
style="color:rgb(249,250,244)">)</span><span
style="color:rgb(255,0,127)">,</span><span
style="color:rgb(207,191,173)"> ChronoUnit</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(207,191,173)">MILLIS</span><span
style="color:rgb(249,250,244)">))</span><span
style="color:rgb(255,0,127)">;</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(255,0,127)">return</span><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(196,140,255)">2</span><span
style="color:rgb(255,0,127)">;</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(249,250,244)">})</span><span
style="color:rgb(255,0,127)">;</span></p><p
style="margin:0px">
</p><p style="margin:0px"><span style="color:rgb(207,191,173)"> scope</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(167,236,33)">join</span><span
style="color:rgb(249,250,244)">()</span><span
style="color:rgb(255,0,127)">;</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(255,255,255)">// get first result, (will not care about exceptions as long as one succeeds)</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> scope</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(167,236,33)">result</span><span
style="color:rgb(249,250,244)">()</span><span
style="color:rgb(255,0,127)">;</span></p><p
style="margin:0px"><span
style="color:rgb(255,0,127)">
</span></p><p style="margin:0px"><span style="color:rgb(207,191,173)"> </span><span
style="color:rgb(255,255,255)">// will throw an exception</span><span
style="color:rgb(255,0,127)">
</span></p><p style="margin:0px"><span style="color:rgb(207,191,173)"> </span><span
style="color:rgb(207,191,173)">fail</span><span
style="color:rgb(255,0,127)">.</span><span
style="color:rgb(190,214,255)">get</span><span
style="color:rgb(249,250,244)">()</span><span
style="color:rgb(255,0,127)">;</span></p><p
style="margin:0px"><span
style="color:rgb(207,191,173)"> </span><span
style="color:rgb(249,250,244)">}</span></p></div>
</div>
</div>
<div dir="ltr"><br>
</div>
<div dir="ltr"><br>
</div>
<div dir="ltr">Essentially, you must use the
`scope.result()` method to retrieve the result
instead of calling the get methods on a particular
subtask<input name="virtru-metadata" type="hidden"
value="{"email-policy":{"disableCopyPaste":false,"disablePrint":false,"disableForwarding":false,"enableNoauth":false,"expandedWatermarking":false,"expires":false,"sms":false,"expirationNum":1,"expirationUnit":"days","isManaged":false,"persistentProtection":false},"attachments":{},"compose-id":"1","compose-window":{"secure":false}}"></div>
</div>
</div>
</div>
</div>
</div>
<br>
<div class="gmail_quote" style="">
<div dir="ltr" class="gmail_attr">On Fri, Oct 27, 2023 at
12:37 PM Eric Kolotyluk <<a
href="mailto:eric@kolotyluk.net" moz-do-not-send="true"
class="moz-txt-link-freetext">eric@kolotyluk.net</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote"
style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div>
<p>Looks good... thanks.</p>
<p>One slight area of confusion for me was, <br>
</p>
<pre><code><T> List<Future<T>> executeAll(List<Callable<T>> tasks)
throws InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
List<? extends Supplier<Future<T>>> futures = tasks.stream()
.map(task -> asFuture(task))
.map(scope::fork)
.toList();
scope.join();
return futures.stream().map(Supplier::get).toList();
}
}
static <T> Callable<Future<T>> asFuture(Callable<T> task) {
return () -> {
try {
return CompletableFuture.completedFuture(task.call());
} catch (Exception ex) {
return CompletableFuture.failedFuture(ex);
}
};
}</code></pre>
<p>And what happens if <code>ShutdownOnSuccess</code> is
called instead. Eventually I reasoned that the right
thing should happen, but there should only ever be one
element in the list. Does the scope guarantee only one
result?<br>
</p>
<ol>
<li>It would be slightly helpful to point this out in a
note so that it is more obvious.</li>
<li>What is less obvious is that with <code>ShutdownOnSuccess</code>
what happens if one or more of the siblings throw an
exception?</li>
<ul>
<li>I would hope that so long at least one task
succeeds, this should not cause the overall success
of the scope to fail.</li>
<li>It would be nice to see this explained more
clearly.</li>
<li> Maybe <code>ShutdownOnSuccess</code> deserves its
own example, discussing possible edge cases.</li>
</ul>
</ol>
<p>Somehow I am remembering Scala 'for comprehensions'
with concurrent tasks that 'yield' a result... 😉</p>
<p>The current situation seems kinda clunky with using one
stream to collect futures, and yet another stream to
collect results. Maybe one of the Java architects hates
such boilerplate, and will come up with an elegant way
to reduce/remove such boilerplate.<br>
</p>
<p>Sincerely, Eric<br>
</p>
<div>On 2023-10-27 7:39 a.m., Mark Reinhold wrote:<br>
</div>
<blockquote type="cite">
<pre><a href="https://openjdk.org/jeps/462"
target="_blank" moz-do-not-send="true"
class="moz-txt-link-freetext">https://openjdk.org/jeps/462</a>
Summary: Simplify concurrent programming by introducing an API for
structured concurrency. Structured concurrency treats groups of related
tasks running in different threads as a single unit of work, thereby
streamlining error handling and cancellation, improving reliability,
and enhancing observability. This is a preview API.
- Mark</pre>
</blockquote>
</div>
</blockquote>
</div>
</div>
</blockquote>
</body>
</html>