Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread pool not resizing

I want to create a cached thread pool, but it acts as a fixed one. Currently I have this code:

public class BackgroundProcesses {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //ExecutorService threadPool2 = Executors.newCachedThreadPool();
        ExecutorService threadPool = new ThreadPoolExecutor(2, 10, 180, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
        for (int i = 0; i < 800; i++) {
            Callable<String> task = new Task();
            threadPool.submit(task);
        }
    }
}

class Task implements Callable<String> {

    @Override
    public String call() throws Exception {
        Thread.sleep(100);
        System.out.println(Thread.currentThread().getName() + " is ready");
        return "";
    }
}

If I run the code I get output:

pool-1-thread-1 is ready
pool-1-thread-2 is ready
pool-1-thread-1 is ready
pool-1-thread-2 is ready
...

Meaning only 2 threads are doing all the work and no new worker threads are added to the pool. Shouldn't the threadpool spawn more threads if tasks are waiting in queue (up to 10 in my case)?

I don't want to use Executors.newCachedThreadPool() because it has practically no upper limit on maximum threads and it has corePoolSize 0. I want to have some threads ready at all times for better responsiveness.

----- edit 1 -----

Thank you Aleksey for the answer. Setting capacity to queue is making it behave as expected, but now I have a new problem.

The amount of background tasks vary a lot. Most of the time 0 but can go up to 50 concurrent tasks for short periods. What would be an efficient way to handle this? Keep in mind most background tasks would be short-lived (< 1s) but a few long lived tasks (> 1min) as well.

If I set my threadpool up like this:

ExecutorService threadPool = new ThreadPoolExecutor(2, 10, 180, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10));

I will most likely get RejectedExecutionException with peak usage. However if I set threadpool up like this:

ExecutorService threadPool = new ThreadPoolExecutor(2, 10, 180, TimeUnit.SECONDS, new LinkedBlockingQueue<>(200));

Then no new worker threads will ever be added because the queue won't max out.

The CPU has at least 4 cores so this would be wasteful in my opinion. And most of the time there isn't any background tasks at all (80% of up time), so keeping a fixed thread pool would also be wasteful in my opinion.

like image 641
Kaarel Purde Avatar asked Sep 27 '22 04:09

Kaarel Purde


1 Answers

ThreadPoolExecutor Javadoc says:

When a new task is submitted in method execute(Runnable), and fewer than corePoolSize threads are running, a new thread is created to handle the request, even if other worker threads are idle. If there are more than corePoolSize but less than maximumPoolSize threads running, a new thread will be created only if the queue is full

Your LinkedBlockingQueue is never full, because it does not have an upper bound on the number of elements. Changing new LinkedBlockingQueue() to new LinkedBlockingQueue(10) would solve that.

like image 90
Aleksey Shipilev Avatar answered Sep 30 '22 06:09

Aleksey Shipilev