<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<p>Hi Stig,<br>
</p>
<p><b>Executors.newVirtualThreadPerTaskExecutor()</b>'s Javadoc
states:<br>
<br>
<i>"Creates an Executor that starts a new virtual Thread for each
task. The number of threads created by the Executor is
unbounded.<br>
<b>This method is equivalent to invoking
newThreadPerTaskExecutor(ThreadFactory) with a thread factory
that creates virtual threads.</b>"</i><br>
<br>
-
<a class="moz-txt-link-freetext" href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/Executors.html#newVirtualThreadPerTaskExecutor()">https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/Executors.html#newVirtualThreadPerTaskExecutor()</a><br>
</p>
<p>And if we look at how `ExecutorService::close()` is specified:<br>
<br>
<i>"<b>Initiates an orderly shutdown in which previously submitted
tasks are executed</b>, but no new tasks will be accepted. <b>This
method waits until all tasks have completed execution and the
executor has terminated.</b>"</i></p>
<p>-
<a class="moz-txt-link-freetext" href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/ExecutorService.html#close()">https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/ExecutorService.html#close()</a><br>
<br>
>This led me to believe that I could write code like that, and
get something that reacts to interrupts promptly. But
unfortunately, the close method on this executor does not
interrupt the two submitted fetches. Instead, if the main thread
in this code is interrupted, the thread will block until the two
fetches complete on their own time, and then it will fail the
request, which seems a little silly. <br>
</p>
<p>No, the specification for ExecutorService::close() further
states:<br>
<br>
<i>"<b>If interrupted while waiting, this method stops all
executing tasks as if by invoking shutdownNow().</b> It then
continues to wait until all actively executing tasks have
completed. Tasks that were awaiting execution are not executed.
The interrupt status will be re-asserted before this method
returns."<br>
</i><br>
</p>
<div class="moz-cite-prefix">Given the above: It looks like you want
to use Structured Concurrency instead of
Executors.newVirtualThreadPerTaskExecutor()</div>
<div class="moz-cite-prefix"><br>
</div>
<div class="moz-cite-prefix">On 2025-12-01 21:16, Stig Rohde Døssing
wrote:<br>
</div>
<blockquote type="cite" cite="mid:CAG09ER0mNxCMnzBdJyiDAk+u32yyP9Lk-n_h1MgdYUqzgkTpMg@mail.gmail.com">
<div dir="ltr">
<div>Hi,</div>
<div><br>
</div>
<div>I stumbled on a minor landmine with
newVirtualThreadPerTaskExecutor, and figured I'd share in case
something can be done to communicate this behavior a little
better, because it caught me by surprise.</div>
<div><br>
</div>
<div>JEP 444 suggests code like the following<br>
<br>
try (var executor =
Executors.newVirtualThreadPerTaskExecutor()) {<br>
var future1 = executor.submit(() ->
fetchURL(url1));<br>
var future2 = executor.submit(() ->
fetchURL(url2));<br>
response.send(future1.get() + future2.get());<br>
} catch (ExecutionException | InterruptedException e) {<br>
response.fail(e);<br>
}<br>
<br>
</div>
<div>This led me to believe that I could write code like that,
and get something that reacts to interrupts promptly. But
unfortunately, the close method on this executor does not
interrupt the two submitted fetches. Instead, if the main
thread in this code is interrupted, the thread will block
until the two fetches complete on their own time, and then it
will fail the request, which seems a little silly. </div>
<div><br>
</div>
<div>Due to how try-with-resources works, the executor is closed
before the catch block is hit, so in order to "stop early"
when interrupted, you'd need to add a nested try-catch inside
the try-with-resources to either interrupt the two futures or
call shutdownNow on the executor when the main thread is
interrupted.</div>
<div><br>
</div>
<div>I know that the structured concurrency API will be a better
fit for this kind of thing, but given that virtual threads are
likely to spend a lot of their time blocking waiting for
something to occur, it seems a little unfortunate that the
ThreadPerTaskExecutor for virtual threads doesn't do
shutdownNow on close when used in the most straightforward
way.</div>
</div>
</blockquote>
<pre class="moz-signature" cols="72">--
Cheers,
√
Viktor Klang
Software Architect, Java Platform Group
Oracle</pre>
</body>
</html>