I'm working on a Java program that uses virtual threads to perform a specific task (a serial communication procedure with jssc). I would like to know if there is a way to pause and resume these virtual threads based on user input. I've read something about 'continuation' but it doesn't seem to be usable yet.
For example, I want the procedure to be paused when the user presses a "pause" button on the program's interface, and it should resume when the user clicks a "play" button.
I'm using Java 21 and I'm not currently using any specific libraries or frameworks for thread management.
Thank you in advance!
Yes, locks & semaphores work the same
Virtual threads behave the same with regard to locks & semaphores. So you can use the same approach with virtual threads as with platform threads.
To quote JEP 444:
Better than pausing: Discard virtual thread
However, you may be missing out on the benefits of virtual threads.
The reason for their invention was to provide cheap threads, meaning very little impact on memory, CPU, JVM, or host OS. Virtual threads are meant to be like facial tissues: When needed, grab a fresh new one, use, and dispose. So rather than pause & resume a virtual thread, consider just disposing of the current one, then launch another when needed again.
Example app
Here is an example app that does just that. When launched, this app beeps once a second. On the console, the user can pause the beeping, and resume the beeping. Or so the user thinks. Pausing really lets the current virtual thread making the sound end its run, and die. Resuming actually launches a new fresh virtual thread to begin again with the beep-per-second.
In modern Java we rarely need to address the
Threadclass directly. Generally best to let an executor service juggle the threads. Here we choose to use an executor service backed by virtual threads.Notice that an executor service is
AutoCloseable. This means we can use try-with-resources syntax to automatically end the executor service.We use a thread-safe collection here to act as a log, gathering feedback during the execution of the app. This is done rather than calling
System.out.printlndirectly as output from those calls does not necessarily appear chronologically on the console when made across threads.When run:
For more info, see What does java.lang.Thread.interrupt() do?.
If we follow strictly our concept of disposable virtual threads, then we do not actually need the
AtomicReferenceused to signal between threads. Instead, we can simplify our code by relying upon theinterruptfeature of threads available here viaFuture#cancel.In the
demomethod, we changed thewhileloop to ado - while.In the nested
Beepertask class, we change thewhiletest towhile ( ! Thread.currentThread( ).isInterrupted( ) )rather than check ourAtomicReference.When run:
Continuations — merely an implementation detail
As for your mention of continuations, that is a lower-level implementation detail behind virtual threads. The Project Loom team has considered exposing their continuation framework to Java programmers, but have not yet decided to do so.
If you are curious about how Loom uses continuations to make Java’s virtual threads so very fast and low-impact, see an interesting 2023-08 talk by Project Loom technical lead, Ron Pressler.
But understand that learning about continuations is entirely optional. Knowing about continuations is unnecessary for making practical use of virtual threads in Java.
Caveat: I am not an expert on Java concurrency. So do your own investigation before relying upon my advice here.