<!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>