41

Executors provides newCachedThreadPool() and newScheduledThreadPool(), but not newCachedScheduledThreadPool(), what gives here? I have an application that receives bursty messages and needs to schedule a fairly lengthy processing step after a fixed delay for each. The time constraints aren't super tight, but I would prefer to have more threads created on the fly if I exceed the pool size and then have them trimmed back during periods of inactivity. Is there something I've missed in the concurrent library, or do I need to write my own?

skaffman
  • 398,947
  • 96
  • 818
  • 769
BD at Rivenhill
  • 12,395
  • 10
  • 46
  • 49

4 Answers4

10

By design the ScheduledThreadPoolExecutor is a fixed size. You can use a single threaded version that submits to a normal ExecutorService for performing the task. This event thread + worker pool is fairly ease to coordinate and the flexibility makes up for the dedicated thread. I've used this in the past to replace TimerTasks and other non-critical tasks to utilize a common executor as a system-wide pool.

Ben Manes
  • 9,178
  • 3
  • 35
  • 39
9

Suggested here Why does ScheduledThreadPoolExecutor only accept a fixed number of threads? workaround:

scheduledExecutor = new ScheduledThreadPoolExecutor(128); //no more than 128 threads
scheduledExecutor.setKeepAliveTime(10, TimeUnit.SECONDS);
scheduledExecutor.allowCoreThreadTimeOut(true);
Community
  • 1
  • 1
Grigory Kislin
  • 16,647
  • 10
  • 125
  • 197
  • 5
    **Caution using this workaround**: consider this from the [documentation of ScheduledThreadPoolExecutor](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html): _"Additionally, it is almost never a good idea to set corePoolSize to zero or use **allowCoreThreadTimeOut** because this may leave the pool without threads to handle tasks once they become eligible to run."_ – rmoestl Mar 03 '15 at 08:18
  • 3
    After poking around with this, I could not get the `ScheduledThreadPoolExecutor` to exhibit this behaviour. With the default implementation, if the thread pool is empty, `ensurePrestart()`, a private method called by all schedule methods, will create a worker to handle the new task. A github gist: https://gist.github.com/Groostav/600edf739a39cbbb33cbd64ad385d621 – Groostav Jul 01 '17 at 22:39
  • 1
    read: this implies that the comment @rmoestl is referencing is erroneous, and that GKislin's strategy is sound. It is still of course very concerning that the docs suggest this isn't a valid strategy, and its entirely possible that I'm missing something. – Groostav Jul 01 '17 at 22:42
3

java.util.concurrent.Executors is nothing more than a collection of static convenience methods that construct common arrangements of executors.

If you want something specific that isn't offered by Executors, then feel free to construct your own instance of the implemention classes, using the examples in Executors as a guide.

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • 4
    Imho this answer is misleading for the stated problem as it suggests that one can simply construct an Executor that meets this particular requirements. But reading the documentation of [ScheduledThreadPoolExecutor](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html) indicates that calling several tuning methods inherited from [ThreadPoolExecutor](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html) "have no useful effect" and thus the desired behaviour seems to be unsupported by `ScheduledThreadPoolExecutor`. – rmoestl Mar 03 '15 at 08:14
-3

Like skaffman says, Executors is only a collection of factory method. if you need a particular instance, you can always check all existing Executor implementors. In your case, i think that calling one of the various constructors of ScheduledThreadPoolExecutor would be a good idea.

Riduidel
  • 22,052
  • 14
  • 85
  • 185