FixedThreadPool vs CachedThreadPool: the lesser of two evils

Daniel picture Daniel · Jul 30, 2013 · Viewed 71.5k times · Source

I have a program that spawns threads (~5-150) which perform a bunch of tasks. Originally, I used a FixedThreadPool because this similar question suggested they were better suited for longer lived tasks and with my very limited knowledge of multithreading, I considered the average life of the threads (several minutes) "long lived".

However, I recently added the capability to spawn additional threads and doing so takes me above the thread limit I set. In this case, would it be better to guess and increase the number threads I can allow or to switch to a CachedThreadPool so I have no wasted threads?

Trying them both out preliminarily, there doesn't seem to be a difference so I'm inclined to go with the CachedThreadPool just to avoid the waste. However, does the life span of the threads mean I should instead picked a FixedThreadPool and just deal with the unused threads? This question makes it seem like those extra threads aren't wasted but I would appreciate the clarification.

Answer

Trevor Freeman picture Trevor Freeman · Jul 30, 2013

A CachedThreadPool is exactly what you should use for your situation as there are no negative consequence to using one for long running threads. The comment in the java doc about CachedThreadPools being suitable for short tasks merely suggest that they are particularly appropriate for such cases, not that they cannot or should not be used for tasks involving long running tasks.

To elaborate further, Executors.newCachedThreadPool and Executors.newFixedThreadPool are both backed by the same thread pool implementation (at least in the open JDK) just with different parameters. The differences just being their thread minimum, maximum, thread kill time, and queue type.

public static ExecutorService newFixedThreadPool(int nThreads) {
     return new ThreadPoolExecutor(nThreads, nThreads,
                                   0L, TimeUnit.MILLISECONDS,
                                   new LinkedBlockingQueue<Runnable>());
 }

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                 60L, TimeUnit.SECONDS,
                                 new SynchronousQueue<Runnable>());
}

A FixedThreadPool does have its advantages when you do in fact want to work with a fixed number of threads, since then you can submit any number of tasks to the executor service while knowing that the number of threads will be maintained at the level you specified. If you explicitly want to grow the number of threads, then this is not the appropriate choice.

This does however mean that the one issue that you may have with the CachedThreadPool is in regards to limiting the number of threads that are running concurrently. The CachedThreadPool will not limit them for you, so you may need to write your own code to ensure that you do not run too many threads. This really depends on the design of your application and how tasks are submitted to the executor service.