I would like my virtual thread is garbage collected when blocking queue, which the thread consumes, is thrown away.
It should work: according to https://openjdk.org/jeps/444,
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. This also means that if a virtual thread is blocked on,
e.g., BlockingQueue.take(), and no other thread can obtain a reference
to either the virtual thread or the queue, then the thread can be
garbage collected — which is fine, since the virtual thread can never
be interrupted or unblocked. Of course, the virtual thread will not be
garbage collected if it is running or if it is blocked and could ever
be unblocked.
See my code
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(100);
Thread thread = fireVirtualConsumer(blockingQueue);
blockingQueue = null;
thread = null;
System.out.println("Blocking queue is: " + blockingQueue + " thread is " + thread);
// here I catch thread dump
TimeUnit.SECONDS.sleep(5);
}
private static Thread fireVirtualConsumer(BlockingQueue<String> blockingQueue) {
return Thread.ofVirtual().start(() -> {
try {
for(;;) {
blockingQueue.take();
}
} catch (InterruptedException e) {
System.out.println("Demo interrupted");
}
});
}
When I catch the heap dump, I see that the ArrayBlockingQueue
is not candidate for GC
java.util.concurrent.ArrayBlockingQueue 0x6059ac1a0 504 B
arg$1 of Demo$$Lambda+0x00000200a1003200 0x6059acf40 520 B
val$task of java.lang.VirtualThread$VThreadContinuation$1 0x6059c1c98 544 B
target of java.lang.VirtualThread$VThreadContinuation 0x6059c1bf8 624 B
cont of java.lang.VirtualThread 0x6059c1728 904 B
key of java.util.concurrent.ConcurrentHashMap$Node 0x6059c2350 936 B
java.util.concurrent.ConcurrentHashMap$Node[16] 0x6059c2300 1,02 kB
table of java.util.concurrent.ConcurrentHashMap 0x6059bfaa8 1,08 kB
map of java.util.concurrent.ConcurrentHashMap$KeySetView 0x6059bfa90 1,1 kB
VTHREADS of jdk.internal.vm.ThreadContainers$RootContainer$TrackingRootContainer, GC Root: Sticky class 0x6059bf9f0 1,22 kB
And VirtualThread also
java.lang.VirtualThread 0x60454dc40 904 B
key of java.util.concurrent.ConcurrentHashMap$Node 0x60454e798 936 B
java.util.concurrent.ConcurrentHashMap$Node[16] 0x60454e748 1,02 kB
table of java.util.concurrent.ConcurrentHashMap 0x60454bfa0 1,08 kB
map of java.util.concurrent.ConcurrentHashMap$KeySetView 0x60454bf88 1,1 kB
VTHREADS of jdk.internal.vm.ThreadContainers$RootContainer$TrackingRootContainer, GC Root: Sticky class 0x60454bee8 1,22 kB
What is wrong? Why virtual thread is visible from CG root when ArrayBlockingQueue is empty, not visible from main and VirtualThread is also not visible main?