3

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.

Olivier
  • 13,283
  • 1
  • 8
  • 24
Piotrold
  • 77
  • 1
  • 6
  • will the `Executors.cachedThreadPool(ThreadFactory threadFactory)` do? "Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available, and uses the provided ThreadFactory to create new threads when needed." – experiment unit 1998X Jun 30 '23 at 08:31
  • yes, but I need scheduling functionality so I would like to use methods like `scheduledExecutorService.scheduleAtFixedRate()` which ScheduledExecutorService offer and plain Executor not. – Piotrold Jun 30 '23 at 08:36
  • Well there are [reasons](https://stackoverflow.com/q/3353002/16034206) as to why scheduledExecutorService is designed the way it is, you would be better off using a cachedThreadPool and writing logic to handle the scheduling yourself. – experiment unit 1998X Jun 30 '23 at 09:01
  • 1
    Don't conflate threads with _tasks._ A thread is an entity that _does_ things. A task is a thing that needs to be done. One does not submit threads to an executor service. One submits tasks. The executor service then usually (but not necessarily always) uses its _own_ thread(s) to perform the given tasks. – Solomon Slow Jun 30 '23 at 12:25
  • 1
    Re, "I would like to follow "one virtual thread per task" principle." That's great if you are creating the virtual threads yourself. But if you're going to use a _scheduled\*_ executor service, then why not trust it to do what's best? The people who write and maintain the JRE generally put a lot of thought into doing what's best. – Solomon Slow Jun 30 '23 at 12:29
  • 1
    \* If you were using a non-scheduled executor, then you might consider that the whole point of virtual threads is to eliminate the _need_ for thread pools. Using a non-scheduled executor (i.e., a thread pool) adds complexity to your program, but it solves a problem, namely, that creating and destroying threads is expensive. But creating and destroying _virtual_ threads is _not_ expensive. So, if you have virtual threads, then why add the complexity of a thread pool? – Solomon Slow Jun 30 '23 at 12:34
  • @SolomonSlow I updated the question. I described what problem exactly I try to solve. But for now, It looks like: `ScheduledExecutorService executor = Executors.newScheduledThreadPool(100, Thread.ofVirtual().factory());` is the best choice for this kind of problem – Piotrold Jun 30 '23 at 19:56

1 Answers1

2

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.

matt
  • 10,892
  • 3
  • 22
  • 34
  • 2
    Just another excuse for the absence of standard API - ok men, change your applications that used scheduler for years (pattern established by JRE in 2004) just because ... why? What is wrong with that task queue (in the scheduler) being polled by virtual (not platform) thread? Sad but it what we have for LTS release... – Vladimir Konkov Jul 25 '23 at 11:06
  • @VladimirKonkov I fully agree with you. This is the best that I found so far but still, it looks more like a workaround, then the actual solution for the problem. – Piotrold Jul 26 '23 at 16:03