Search code examples
javamultithreadingscheduled-tasksexecutorservicevirtual-threads

How to use virtual threads with ScheduledExecutorService


I want to use virtual threads introduced in Java 19 and ScheduledExecutorService. I need to schedule some threads to be run every minute. I know that I can use something like this: ScheduledExecutorService executor = Executors.newScheduledThreadPool(100, Thread.ofVirtual().factory()); But it looks like I'm forced to set pool size.

I'm looking for a fabric method similar to this: ScheduledExecutorService executor = Executors.newScheduledThreadPool(Thread.ofVirtual().factory()); But I can't find it. I would like to follow "one virtual thread per task" principle and not be forced to set a fixed number of threads in the pool. Do you know if I can use ScheduledExecutorService in that way? Or some alternative exists which are adapted to virtual threads?

UPDATE

Let me elaborate on what problem I try to solve. So I need to create more than 1000 tasks (I don't know the exact number, I can only estimate it). Which should be run periodically. Some need to be run every minute, some every two minutes, etc.

Those tasks will perform I/O operations (network requests). So virtual threads look like a good choice. But I need some scheduling functionality to achieve it. By choosing ScheduledExecutorService I can use methods like: scheduledThreadPoolExecutor.scheduleAtFixedRate(runnableTask, 60, 60, TimeUnit.SECONDS )

If I would not need scheduling I would simply create an executor like that: var executor = Executors.newVirtualThreadPerTaskExecutor() But plain ExecutorService doesn't provide any scheduling functionality. And I would be forced to implement scheduling on my own.

So for now the best solution I found is: Executors.newScheduledThreadPool(1000, Thread.ofVirtual().factory()); This generally looks good but I wonder if some other solution in Java API exists which allows me to create ScheduledExecutor but I will not be forced to set the size of a thread pool. Which for me looks a little bit strange when we consider virtual threads.


Solution

  • I think you want to consider offloading the work to virtual threads, and schedule the work with a sheduler.

    ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor()
    ExecutorService donkey = Executors.newVirtualThreadPerTaskExecutor()
    

    Then when you want to schedule a task.

    void schedule(Runnable command, long delay, TimeUnit unit){
        scheduler.schedule( ()->donkey.execute(command), delay, unit);
    }
    

    You really don't want your scheduling thread to be split up amongst virtual threads because you want your scheduling thread to be free to schedule more tasks.