<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <blockquote type="cite"
      cite="mid:2F8B19AF-764A-46AF-90FB-A6A76E7EDFCC@oracle.com">
      <blockquote type="cite">
        <pre class="moz-quote-pre" wrap="">On 2 Aug 2023, at 12:26, Dr Heinz M. Kabutz <a class="moz-txt-link-rfc2396E" href="mailto:heinz@javaspecialists.eu"><heinz@javaspecialists.eu></a> wrote:

I've been doing this for a while (and am using the approach on my javaspecialists.eu website):
Executors.newSingleThreadScheduledExecutor(
Thread.ofVirtual().factory())

It works very well indeed.
Regards

Heinz
— 
</pre>
      </blockquote>
      <pre class="moz-quote-pre" wrap="">
I would advise against that and in favour of the approach in the Stack Overflow answer. Remember that a virtual thread should normally only ever execute a single task that’s been submitted to an Executor. 

I understand that your intent is good, and that you probably just want to use the convenient “fixed rate” methods of ScheduledExecutorService to run what is *conceptually* a single task, but many of the problems we see with people misusing virtual threads and not getting good results are due to them not internalising this idea that a virtual thread is a single task, so I would suggest not to show this kind of usage to virtual thread beginners.

— Ron
</pre>
    </blockquote>
    <p>What about this use case for virtual threads?</p>
    <p>        Cleaner cleaner =
      Cleaner.create(Thread.ofVirtual().factory());<br>
    </p>
    <p>(Not that I typically need Cleaners, but if I did, I wouldn't
      want a platform thread bound up just for that.)</p>
    <p>Could you perhaps expand a bit on the problems that are caused by
      my solution above? I can think of a few, but not sure if that is
      what you meant. For example:<br>
    </p>
    <p>1. One task using a lot of CPU and thus preventing the unmounting
      of a carrier thread (this would be the same with the SOF solution
      - actually their approach may be even worse, because we could have
      successive tasks that run and overlap each other).</p>
    <p>2. Virtual carrier threads are daemons, so the timer would not
      prevent the JVM from shutting down. However, I would typically
      make timers to use daemon threads anyway.</p>
    <p>What else do you see going wrong?</p>
    <p>Here is an experiment to demonstrate point 1, using the donkey
      approach from SOF. Excuse the copy & paste code please - could
      do with some refactoring:</p>
    <div style="background-color:#2b2b2b;color:#a9b7c6">
      <pre style="font-family:'JetBrains Mono NL',monospace;font-size:30,0pt;"><span style="color:#cc7832;">import </span>java.time.*<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">import </span>java.util.concurrent.*<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">
</span><span style="color:#cc7832;">public class </span>VirtualTimers {
    <span style="color:#cc7832;">public static void </span><span style="color:#ffc66d;">main</span>(String... args) <span style="color:#cc7832;">throws </span>InterruptedException {
        <span style="font-style:italic;">test</span>(<span style="color:#6a8759;">"platform thread timer"</span><span style="color:#cc7832;">, </span>Executors.<span style="font-style:italic;">newSingleThreadScheduledExecutor</span>())<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">        </span><span style="font-style:italic;">test</span>(<span style="color:#6a8759;">"virtual thread timer"</span><span style="color:#cc7832;">, </span>Executors.<span style="font-style:italic;">newSingleThreadScheduledExecutor</span>(Thread.<span style="font-style:italic;">ofVirtual</span>().factory()))<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">        </span><span style="font-style:italic;">test2</span>(<span style="color:#6a8759;">"virtual thread timer with donkey"</span><span style="color:#cc7832;">, </span>Executors.<span style="font-style:italic;">newSingleThreadScheduledExecutor</span>()<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">                </span>Executors.<span style="font-style:italic;">newVirtualThreadPerTaskExecutor</span>())<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">    </span>}

    <span style="color:#cc7832;">private static void </span><span style="color:#ffc66d;">test</span>(String description<span style="color:#cc7832;">, </span>ScheduledExecutorService timer)
            <span style="color:#cc7832;">throws </span>InterruptedException {
        System.<span style="color:#9876aa;font-style:italic;">out</span>.println(description)<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">        try </span>(timer) {
            timer.scheduleWithFixedDelay(<span style="color:#cc7832;">new </span>Runnable() {
                <span style="color:#cc7832;">private int </span><span style="color:#9876aa;">counter</span><span style="color:#cc7832;">;
</span><span style="color:#cc7832;">
</span><span style="color:#cc7832;">                public void </span><span style="color:#ffc66d;">run</span>() {
                    System.<span style="color:#9876aa;font-style:italic;">out</span>.println(<span style="color:#6a8759;">"Starting task " </span>+ ++<span style="color:#9876aa;">counter</span>)<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">                    try </span>{
                        Thread.<span style="font-style:italic;">sleep</span>(Duration.<span style="font-style:italic;">ofMillis</span>(<span style="color:#6897bb;">1500</span>))<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">                    </span>} <span style="color:#cc7832;">catch </span>(InterruptedException e) {
                        <span style="color:#cc7832;">throw new </span>CancellationException(<span style="color:#6a8759;">"interrupted"</span>)<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">                    </span>}
                    System.<span style="color:#9876aa;font-style:italic;">out</span>.println(<span style="color:#6a8759;">"Finished task " </span>+ <span style="color:#9876aa;">counter</span>)<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">                </span>}
            }<span style="color:#cc7832;">, </span><span style="color:#6897bb;">1</span><span style="color:#cc7832;">, </span><span style="color:#6897bb;">1</span><span style="color:#cc7832;">, </span>TimeUnit.<span style="color:#9876aa;font-style:italic;">SECONDS</span>)<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">
</span><span style="color:#cc7832;">            </span>Thread.<span style="font-style:italic;">sleep</span>(Duration.<span style="font-style:italic;">ofSeconds</span>(<span style="color:#6897bb;">10</span>))<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">        </span>}
        System.<span style="color:#9876aa;font-style:italic;">out</span>.println()<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">    </span>}
    
    <span style="color:#cc7832;">private static void </span><span style="color:#ffc66d;">test2</span>(String description<span style="color:#cc7832;">, </span>ScheduledExecutorService timer<span style="color:#cc7832;">, </span>ExecutorService virtualThreadService)
            <span style="color:#cc7832;">throws </span>InterruptedException {
        System.<span style="color:#9876aa;font-style:italic;">out</span>.println(description)<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">        try </span>(timer<span style="color:#cc7832;">; </span>virtualThreadService) {
            Runnable task = <span style="color:#cc7832;">new </span>Runnable() {
                <span style="color:#cc7832;">private int </span><span style="color:#9876aa;">counter</span><span style="color:#cc7832;">;
</span><span style="color:#cc7832;">
</span><span style="color:#cc7832;">                public void </span><span style="color:#ffc66d;">run</span>() {
                    System.<span style="color:#9876aa;font-style:italic;">out</span>.println(<span style="color:#6a8759;">"Starting task " </span>+ ++<span style="color:#9876aa;">counter</span>)<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">                    try </span>{
                        Thread.<span style="font-style:italic;">sleep</span>(Duration.<span style="font-style:italic;">ofMillis</span>(<span style="color:#6897bb;">1500</span>))<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">                    </span>} <span style="color:#cc7832;">catch </span>(InterruptedException e) {
                        <span style="color:#cc7832;">throw new </span>CancellationException(<span style="color:#6a8759;">"interrupted"</span>)<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">                    </span>}
                    System.<span style="color:#9876aa;font-style:italic;">out</span>.println(<span style="color:#6a8759;">"Finished task " </span>+ <span style="color:#9876aa;">counter</span>)<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">                </span>}
            }<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">            </span>timer.scheduleWithFixedDelay(() -> <span style="color:#b389c5;">virtualThreadService</span>.execute(<span style="color:#b389c5;">task</span>)<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">                    </span><span style="color:#6897bb;">1</span><span style="color:#cc7832;">, </span><span style="color:#6897bb;">1</span><span style="color:#cc7832;">, </span>TimeUnit.<span style="color:#9876aa;font-style:italic;">SECONDS</span>)<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">
</span><span style="color:#cc7832;">            </span>Thread.<span style="font-style:italic;">sleep</span>(Duration.<span style="font-style:italic;">ofSeconds</span>(<span style="color:#6897bb;">10</span>))<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">        </span>}
        System.<span style="color:#9876aa;font-style:italic;">out</span>.println()<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">    </span>}
}
</pre>
    </div>
    <p></p>
    <p>Not only do we see the tasks overlapping each other, but we also
      have to now ensure that counter is thread-safe.</p>
    <p>platform thread timer<br>
      Starting task 1<br>
      Finished task 1<br>
      Starting task 2<br>
      Finished task 2<br>
      Starting task 3<br>
      Finished task 3<br>
      Starting task 4<br>
      Finished task 4<br>
      <br>
      virtual thread timer<br>
      Starting task 1<br>
      Finished task 1<br>
      Starting task 2<br>
      Finished task 2<br>
      Starting task 3<br>
      Finished task 3<br>
      Starting task 4<br>
      Finished task 4<br>
      <br>
      virtual thread timer with donkey<br>
      Starting task 1<br>
      Starting task 2<br>
      Finished task 2<br>
      Starting task 3<br>
      Finished task 3<br>
      Starting task 4<br>
      Finished task 4<br>
      Starting task 5<br>
      Finished task 5<br>
      Starting task 6<br>
      Finished task 6<br>
      Starting task 7<br>
      Finished task 7<br>
      Starting task 8<br>
      Finished task 8<br>
      Starting task 9<br>
      Finished task 9<br>
      Finished task 9<br>
      <br>
    </p>
    <p><br>
    </p>
    <p><br>
    </p>
    <p><br>
    </p>
  </body>
</html>