Hacker News new | ask | show | jobs
by avodonosov 885 days ago
Sorry, the first sentence is a mis-informing wording.

The `synchronized` pins the thread only when from within of the `synchronized` the program calls a blocking operation that would normally unmount the virtual thread, like blockingQueue.take() or similar. (Which is not a sane coding practice). It's because the unmounting, as it's implemented today, does not work well with synchronized.

It's better if people read JEP 444 than rely on forum comments, to avoid being misinformed.

Speaking of long-running - even without synchronized, a long running code keeps the native thread occupied, until some blocking operation is called. So an endless loop that does not call a virtual-thread-ready blocking operation will occupy the native thread forever.

Java virtual threads are a kind of cooperative multithreading - another virtual thread only gets chance to kick-in when some current virtual thread reaches specific blocking operations. In contrast to preemptive multi-threading with native threads.

So I agree with your conclusion. Virtual threads can not (yet?) be blindly used as a drop-in replacement of native threads for existing code. And the new code needs to take their specifics into account.

BTW, another method I discovered to block the native carrier thread that executes a virtual thread is to call blocking reading through FileInputStream, for example reading from the console. The FileInputStream does not implement virtual thread parking at all (yet?).

2 comments

The issue in this case isn't actually the synchronized block. The thread is blocked on Object.wait, which releases the monitor before sleeping. The problem is that Object.wait is implemented in native code still, which pins the thread. The idea is that these days wait isn't exactly deprecated but there are better concurrency tools available, so they upgraded those first, leaving the Java 1 style concurrency tools for later. And Java 1 style concurrency has been improved on but is hardly insane, it can work well enough in many situations and is sometimes the basis for higher level concurrency utilities.
By long running I just meant anything that was not fast compute. I was more focused on finding the reference link so I agree my wording wasn’t clear.

Go started without preemption and added it later. The Java team has indicated a similar path, so we might see that tackled in the future. I think they could do that using safe points or JEP 312‘s handshakes, so it’s not infeasible.

For file io they wanted to explore io_ring and they might need to add a loom friendly resolver for JEP 418. There is just so much left, like scalable timers, that I think it’s going to be a long time until VTs will be a good default choice.