Cooperative vs preemtive scheduling of virtual theads

Andrey Lomakin lomakin.andrey at
Tue Jun 9 08:16:08 UTC 2020

> For one, even if we guaranteed class loading doesn't introduce a scheduling
> point, you wouldn't be able to rely on HashMap code not having any,
> because the
> existence of such scheduling points are a hidden implementation detail of
> HashMap that could change from one version to another. That's because
> scheduling
> is not cooperative, and code is not made aware of scheduling point in code
> it
> calls via, say, the type checker. The reason scheduling isn't cooperative
> is
> that that would have resulted in a split world, duplicate APIs and no
> forward
> compatibility. So you cannot rely on third-party code not having scheduling
> points regardless of class loading.

Sure, that is why I want to understand/discuss the level of abstraction on
which Loom project works "by design" so to say.

As I can see it, there are two possible variants for the case when a single
thread carrier is used. The first preemption can be performed only in the
places which are visible for the developer from inspection of source code.
Like lock/unlock and IO calls. Sure there is no control over the code
directly by the developer where a developer can introduce the "wait"
keyword (but Thread.yield in current implementation looks very close to
such method). But this approach allows developer, who wants to create code
as performant as possible, to have more control on insertion of memory
fences in one form or another to ensure data consistency. It also opens the
way to use for example collections of primitive types and data structures
which otherwise would be very hard to use. Sure you can not tell by the
signature of the function whether it can be used by several virtual threads
or not, but it seems quite unlikely that HashMap will become unsafe
eventually as the other in-memory data structures. Also, once the concept
of virtual threads is introduced possibility or absence of possibility to
use data structure inside of virtual threads will be reflected inside of
its contract. ConcurrentHashMap is declared to be thread-safe not because
of type checker inspection, obviously, but because that is a part of its
contract. The other approach is to introduce scheduling points in the
"hidden" places like loading of class or maybe some other JVM
implementation dependant parts of the code. The last case means that
essentially you work with virtual threads as with normal threads with the
exception of the fact that the amount of them is virtually unlimited, which
is itself a big advantage of course.

Each approach has its advantages and disadvantages. I hope that probably
you may consider using the first of described approaches (with scheduling
points are clearly recognisable from inspection of source code), especially
taking in account that right now, as I can see the state of the
implementation, exactly this approach is used but with theoretical bound to
handle "hidden" scheduling points too. Even if in such hidden points
virtual threads will not be switched, I dare to suppose that they happen so
rarely on JDK implementations that it will not affect scalability or
performance numbers at all.

In any way or another Loom is very big step forward for the Java world.
Hope to see it included into primary branch of JDK ASAP.

On Tue, Jun 9, 2020 at 7:15 AM David Holmes <david.holmes at> wrote:

> On 9/06/2020 12:52 am, Ron Pressler wrote:
> > You should not make any assumptions about where scheduling points are.
> Thread.yield
> > is not currently specified, but we *may* specify it so that it
> guarantees returning
> > to the scheduler.
> >
> > You *can* assume that a virtual thread is scheduled by its assigned
> scheduler.
> > Therefore, if a scheduler makes use of a single thread, your memory
> accessed are
> > fully-ordered, and you can then use, say, HashMap instead of
> ConcurrentHashMap for
> > threads scheduled by that scheduler. For more interesting
> synchronisation among your
> > threads, you can use locks, which are quite fast when uncontended.
> But I would not advise/encourage programmers to make any general
> assumptions about what scheduler (and its characteristics) may be
> managing their virtual threads. Concurrency-safety for shared objects
> should be achieved through appropriate synchronization mechanisms, not
> by relying on a thread not being preempted within a critical region.
> Cheers,
> David
> -----
> > Could you give an example where this could be insufficient?
> >
> > — Ron
> >
> >
> >
> > On 8 June 2020 at 14:48:55, Andrey Lomakin (lomakin.andrey at
> (mailto:lomakin.andrey at wrote:
> >
> >>> For
> >>> example, any call might be to code that loads new classes, thus
> >>> blocking. So, in principle, any call site can switch tasks.
> >>
> >> And one more question, is it situation which described by Andrew really
> holds ? I thought that executors by current design does not recognize such
> situations (which for example causes the current problem with synchronized)
> >> and do not switch execution of virtual theads and that happens during
> direct calls to the locks and during calls of IO operations ? And is it
> possible that this behaviour will be kept as the "by design" or can be
> changed once project will evolve ? I mean is it true that during exectuion
> of such operation as class loading execution of one virtual thread will be
> swithced to the execution of other virtual thread, especially if the backed
> by the single thread carrier ?
> >>
> >>
> >> On Mon, Jun 8, 2020 at 4:33 PM Andrey Lomakin wrote:
> >>> Hi,
> >>> Thank you for the very useful feedback.
> >>>
> >>>> Does Thread.yield have defined semantics for virtual threads?
> >>>
> >>> That is exactly question which I wanted to ask too. Becuase in quasar
> its implementation looked close to the "wait" key word when you give up
> processor time to the other waiting virtual thread.
> >>>
> >>> As for feedback , I have made migration just a few days ago. Which was
> a quite smooth.
> >>> So I did not run benchmarks yet. But on some of the tests I see about
> 1.5 times speed up (the ones which generate high rate of asynchronous calls
> to the file IO).
> >>>
> >>
> >>
> >>
> >>
> >> --
> >> Best regards,
> >> Andrey Lomakin.
> >>
> >

Best regards,
Andrey Lomakin.

More information about the loom-dev mailing list