<div dir="ltr">I agree Robert, that's my understanding from Alan's previous response:<div><br></div><div>* when blocked, a VT is referenced by the scheduler or wait lists on locks, etc</div><div>* when running, a VT is referenced by the carrier thread.</div><div><br></div><div>From a life-cycle point of view, a VT "is a" Thread, as you correctly say.</div><div><br></div><div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, 25 Jul 2024 at 15:52, Robert Engels <<a href="mailto:robaho@icloud.com">robaho@icloud.com</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 style="overflow-wrap: break-word;">If it is blocked reading a socket, it is not on a CarrierThread (i.e. blocked not running) so there is no strong reference from the CarrierThread to the VirtualThread in this case.<div><br></div><div>I am fairly certain that the scheduler/blocking handler is what maintains the strong thread references in this case.<br><div><br><blockquote type="cite"><div>On Jul 25, 2024, at 8:49 AM, Matthew Swift <<a href="mailto:matthew.swift@gmail.com" target="_blank">matthew.swift@gmail.com</a>> wrote:</div><br><div><div dir="ltr">Thanks for the quick response Alan. A couple of comments:<br><br><div>> You can specify a ThreadFactory to newThreadPerTaskExecutor so you can</div>> set the thread name if you need it. Virtual threads are meant to be<br>> lightweight and numerous so don't get a name by default. For many cases,<br>> this is okay as the they have a thread ID which will identity them in<br>> thread dumps and elsewhere.<br><br>That may be so, but it's not very flexible, unless I'm missing something, because it's not possible to derive the thread name from the task itself. Said otherwise, a ThreadFactory lets you create very generic thread names like "HTTP Connection #1" ahead of time, but doesn't let you derive a rich name from the Runnable itself, like "HTTP Connection from 1.2.3.4 to 5.6.7.8 on port 8080". I tried cheating a bit by relying on the toString() of the Runnable, but sadly this doesn't work because the executor wraps the provided Runnable before calling the thread factory (see ThreadPerTaskExecutor#start(java.lang.Runnable)).<div><br></div><div>> A virtual thread that is blocked reading from a Socket will continue<br>> when there are bytes to read, the peer closes the connection, some I/O<br>> exception, or the thread is interrupted. So it will be strongly reachable.<br></div><div><br></div><div>Ah, of course, silly me. And, following from that, the VT is strongly reachable when running because it is directly referenced by the carrier thread itself.</div><div><br></div><div>Thanks</div><div>Matt</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, 25 Jul 2024 at 14:55, Alan Bateman <<a href="mailto:Alan.Bateman@oracle.com" target="_blank">Alan.Bateman@oracle.com</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"><br>
<br>
On 25/07/2024 13:21, Matthew Swift wrote:<br>
> Hmm, I'm starting to think I may have fallen into the same trap here <br>
> as Michal.<br>
><br>
> I've been using virtual threads similar to platform threads for <br>
> performing IO tasks asynchronously.<br>
><br>
> Background: originally, I was using <br>
> Executors#newVirtualThreadPerTaskExecutor to run these tasks, which <br>
> was fine because the Executor tracks the virtual threads it creates in <br>
> order to support shutdown. However, from an observability point of <br>
> view I've found the executor to be a bit frustrating because it is <br>
> impossible to set the thread name before the thread is scheduled to <br>
> run[1].<br>
You can specify a ThreadFactory to newThreadPerTaskExecutor so you can <br>
set the thread name if you need it. Virtual threads are meant to be <br>
lightweight and numerous so don't get a name by default. For many cases, <br>
this is okay as the they have a thread ID which will identity them in <br>
thread dumps and elsewhere.<br>
<br>
<br>
> This means that under heavy load where the FJ pool is busy a thread <br>
> dump shows many unnamed threads, which are waiting to be scheduled for <br>
> the first time. Admittedly, this is only a minor annoyance because I'm <br>
> more interested in the threads that are clogging up the FJ pool than <br>
> the ones which are waiting to use it, even so it'd be nice to have an <br>
> overall picture of what's active and what's queued (note also thread <br>
> names are included in JFR events, which is super helpful).<br>
<br>
With the Loom EA builds [1] you can use `jcmd <pid> <br>
Thread.vthread_summary` to get a summary view of all thread grouping so <br>
you get thread counts, a summary of the scheduler, timers, and any <br>
socket I/O that it outstanding. We would like to bring this diagnostic <br>
command into the main line JDK at some point.<br>
<br>
><br>
> To remedy this, I've switched away from using an Executor and now I <br>
> just use "Thread.ofVirtual().name(initialName).start(task)". However, <br>
> I don't think all of the tasks are strongly reachable - some are "fire <br>
> and forget" tasks (e.g. async resource cleanup), so I may be <br>
> inadvertently relying on the JVM's observability support to keep these <br>
> tasks alive until they complete, which seems a bit brittle. In fact, <br>
> now that I think of it, it may not even be limited to fire and forget <br>
> tasks. A VT that is reading messages from a Socket could be GC'd<br>
A virtual thread that is blocked reading from a Socket will continue <br>
when there are bytes to read, the peer closes the connection, some I/O <br>
exception, or the thread is interrupted. So it will be strongly reachable.<br>
<br>
-Alan<br>
<br>
[1] <a href="https://jdk.java.net/loom/" rel="noreferrer" target="_blank">https://jdk.java.net/loom/</a><br>
</blockquote></div>
</div></blockquote></div><br></div></div></blockquote></div>