Custom Schedulers: Customize current time and timed waits

Mike Hearn michael.hearn at oracle.com
Mon Jun 23 08:11:41 UTC 2025


At the moment I’m working on a project that does something similar, although it’s internal and it uses the Espresso continuations API rather than modifying Loom. Porting it to the custom scheduler support in Loom is on the list of things to try. I suspect it won't fit because our alternative threads are different enough that we can’t use java.lang.Thread as a base class. We also have our own wait APIs and leave the JDK’s alone, partly because the semantics and features of our waits are different. Once you get into changing the semantics of built-in operations, which I guess a custom scheduler would very likely do, you’re going to either lose compatibility or lose the ability to add the features you want.

One of the features we use this for is deterministic testing. The main issue you’ll face is the lack of dependency injection in the Java standard library. We build on Micronaut to avoid that problem, and so you can @Inject an InstantSource to get a virtualized clock that can be advanced by test code, and our Thread.sleep replacement respects it. It’s not ideal - obviously if a busy-wait loop occurs inside a library then you have to modify the library to make that hookable. However, you probably have to modify it anyway if the library actually looks at anything expecting the time to have advanced (e.g. if the wait is because of a real delay in an external system). One of the advantages of building at a higher level like Micronaut or Spring is the large consistent library of dependency-injectable things. A lot of the modifications have been done for you already. For instance, you can replace the HTTP client beans and override network timeouts that way. You can also inject j.u.c.Lock implementations.

For deterministic testing you don’t need custom schedulers for virtual threads. If you can control the wait and clock APIs, you can just adjust their parameters. The deterministic testing in our project is more useful because it interacts with the custom wait APIs. It would still be nice if Instant.now() and the lock constructors were using an SPI. But this observations takes you in the direction of wishing that Java had better support for dependency injection. It’s a big part of the most popular Java frameworks. The SPI pattern is expensive enough to implement that many parts of the standard library don’t use it.

On 23 Jun 2025, at 00:24, Quinn Klassen <quinn.klassen at temporal.io> wrote:

Yep! I understand nothing has been decided yet. I just saw https://github.com/openjdk/loom/blob/fibers/loom-docs/CustomSchedulers.md/ so I built the JVM over the weekend and was experimenting with it since I think the library I maintain has a interesting use case for schedulers.

For timed operations ideally I would like the virtual thread to request the scheduler it wants to do a timed operation and the scheduler decides how to accomplish this. That may be too high level an interface to add since it looks like more libraries use `java.util.concurrent.locks.LockSupport`. This is my first time looking at the implementation of some of these low level calls, but maybe it would be more realistic to allow a pluggable time source and interception of these parking utilities.

On Sun, Jun 22, 2025 at 12:10 PM Alan Bateman <alan.bateman at oracle.com<mailto:alan.bateman at oracle.com>> wrote:


On 22/06/2025 18:07, Quinn Klassen wrote:
> :
>
> Experimenting with the custom schedules it seems like we now could
> control how threads are scheduled and executed (amazing!), but we
> still can't control the current time or how threads sleep. For example
> if a thread with a custom scheduler calls `Thread.sleep` there is no
> way for the scheduler to control when that will return, even if the
> scheduler tries to unpark the thread the `for` loop in
> `VirtualThread.sleepNanos` will keep parking it. In other
> languages that support a custom scheduler for tasks like Python,
> Javascript, Dotnet, Rust or Ruby this sort of behaviour is customizable.
>
> Is there a way currently to customize this behaviour that I
> have missed or would this be something the team would be open to
> exploring in the future?

Just to say that this project hasn't decided whether to expose anything
on schedulers at this time. There is some basic support in the loom repo
for experimenting and to get more insight into the topic - is that what
you are experimenting with?

Timed operations, e.g. timed-Object.wait, sleep, ... have to deal with
spurious wakeup. Are you looking to advance the time and have these
operations complete early? Or maybe are looking for all time sources to
be pluggable? Or maybe you are looking for the scheduler to know that a
virtual thread is doing a timed operation?

-Alan

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/loom-dev/attachments/20250623/afbec6be/attachment-0001.htm>


More information about the loom-dev mailing list