<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr">> In some cases then having the producer offering a special element to mean "done" can work as a signal to the consumer to shutdown.<br></div><div dir="ltr"><br></div><div>If the producer decides about shutdown, poison pill signal is a well known solution: simple and synchronization-less. If the other party decides to shut down, the poison pill does not work. Shutdown needs synchronization - or ephemeral VT shutdowned by GC.<br></div><div><br></div><div>Regardless of the main issue, I understand that VT GC is problematic. JEP 444 is modified and GC paragraph is removed.</div><div>VT created by Thread API is strongly referenced to avoid finalization problems</div><div>VT created by Executors.newVirtualThreadPerTaskExecutor() or Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory()) are not strongly referenced due oscillating nature of Executor. Moreover, Executor and submit product Future is AutoCloseable. Being autocloseable + try-with-resource means it is easy to avoid finalization problems in code.</div><div><br></div><div>Before try-with-resources, it was well known that some resources, like file descriptors, should not be released by GC. It was the developer's responsibility to close unused file descriptors. Try-with-resources simplifies safe implementation, but the rule is still valid. If releasing something by GC is problematic, it is the developer responsibility to provide safe implementation.</div><div><br></div><div>In my opinion, wrong decisions are made. </div><div><br></div><div>Having all VT ephemeral simplifies the system and allows a simpler programming model. If releasing resources by GC is problematic, it should be a developer problem, not JVM problem.</div><div><br></div><div>If some VT are strongly referenced and some not, and this behavior is undocumented, whole system is unpredictable for developers, who are not subscribers of this group</div><div><br></div><div>Thanks everybody for collaboration</div><div><br></div><div>PS. I JEP 444 I still see GC root paragraph:<br><br><span style="color:rgb(0,0,0);font-family:"DejaVu Sans","Bitstream Vera Sans","Luxi Sans",Verdana,Arial,Helvetica;font-size:13.3333px">Unlike platform thread stacks, virtual thread stacks are not GC roots. Thus the references they contain are not traversed in a stop-the-world pause by garbage collectors, such as G1, that perform concurrent heap scanning.</span><br></div><div><span style="color:rgb(0,0,0);font-family:"DejaVu Sans","Bitstream Vera Sans","Luxi Sans",Verdana,Arial,Helvetica;font-size:13.3333px"><br></span></div><div>What does it mean? I do not understand this paragraph. Will G1 clean VT or not?<br></div></div></div></div></div></div></div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">czw., 11 lip 2024 o 11:00 Alan Bateman <<a href="mailto:Alan.Bateman@oracle.com" target="_blank">Alan.Bateman@oracle.com</a>> napisał(a):<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><u></u>
<div>
On 10/07/2024 20:56, Michal Domagala wrote:<br>
<blockquote type="cite">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">Hi,</div>
<div dir="ltr"><br>
</div>
<div dir="ltr">My issue is accepted as <a href="https://bugs.java.com/bugdatabase/view_bug?bug_id=JDK-8336061" target="_blank">Bug ID:
JDK-8336061 Virtual threads cannot be GC'ed
before they terminate (java.com)</a> and solved
as documentation defect.<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
<br>
You can view the issue in JBS here:
<a href="https://bugs.openjdk.org/browse/JDK-8336061" target="_blank">https://bugs.openjdk.org/browse/JDK-8336061</a><br>
<br>
As noted, we missed an update to a paragraph when copying text from
JEP 425/436 to JEP 444 so it wasn't aligned with the change
summarized in the History section of JEP 444. That has been fixed.
Otherwise, we can only close the JBS issue for now as support for
some kind of ephemeral threads is definitely future exploration.<br>
<br>
<blockquote type="cite">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div><br>
</div>
<div>Still one issue is not clear to me. Is VT
strongly referenced because being blocked and
GC'ed is not useful or is problematic to
implement?</div>
<div><br>
</div>
<div>There were voices in discussion that VT GC
is surprising for developers. For that reason I
showed my case. I wanted to present that
"closing" blocking queue by nullifying and GC
does not need synchronization.
Unsynchronized code is less prone to errors than
code with synchronization.</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
<br>
In some cases then having the producer offering a special element to
mean "done" can work as a signal to the consumer to shutdown. Some
form of closable channel would be similar. I think this project has
a good handle on possible use-cases so we know well that it's not as
simple as this in some cases.<br>
<br>
In the Golang world the phrases used are "forgotten sender" and
"abandoned receiver" when goroutines "leak". This seems to lead to
complicated recipes for signalling and shutdown. Java has had
threads since JDK 1.0 and it doesn't seem to arise as often, one
reason could be that you can keep a reference to a Thread, another
might be that the serviceability/observability support is good so it
is possible to identify orphaned threads and their stack traces,
maybe reason about why they did not terminate when expected.<br>
<br>
<blockquote type="cite">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div><br>
</div>
<div>But there are voices that garbage collection
"alive" VT is problematic: "Finalization is one
topic. Another is Cleaner actions that may run
while a resource is in an inconsistent state." I
don't know this area so I can't deny it.</div>
<div><br>
</div>
<div>I checked that the blocked task created by <span style="font-family:"JetBrains Mono",monospace;color:rgb(0,0,0)">Executors</span><span style="font-family:"JetBrains Mono",monospace;color:rgb(8,8,8)">.</span><span style="font-family:"JetBrains Mono",monospace;color:rgb(8,8,8);font-style:italic">newVirtualThreadPerTaskExecutor</span><span style="font-family:"JetBrains Mono",monospace;color:rgb(8,8,8)">().submit()</span> is
GCed.</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
<br>
Considerable time was spent on this topic before making virtual
threads a permanent feature in JDK 21. We decided to leave this as
is for now. In the case of a Thread-Per-Task-Executor (TPTE) then it
keeps a reference to all threads executing tasks. It has to because
of shutdownNow or close that may have to interrupt all threads. A
TPTE is typically stored somewhere, often a static final field, or
it will be used with try-with-resources. So once a TPTE is strongly
reachable then it will ensure that all virtual threads executing
tasks in that executor are keep reachable. There is a similar story
for other "unowned" executor service implementations. For now,
unowned executor services are weakly tracked for observability
purposes. There is an argument that they should be strongly tracked
when there is at least one thread but that adds some bookkeeping
overhead, esp. when oscillating between zero and a single thread. So
everything you are probing here is possible future work.<br>
<br>
-Alan<br>
<br>
</div>
</blockquote></div>