线程池不调整大小

Thread pool not resizing

我想创建一个缓存线程池,但它充当固定线程池。目前我有这个代码:

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 "";
    }
}

如果我 运行 我得到输出的代码:

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

这意味着只有 2 个线程在做所有的工作,并且没有新的工作线程被添加到池中。如果任务在队列中等待(在我的例子中最多 10 个),线程池不应该生成更多线程吗?

我不想使用 Executors.newCachedThreadPool() 因为它几乎没有最大线程上限并且它有 corePoolSize 0。我想随时准备好一些线程以获得更好的响应能力.

----- 编辑 1 -----

谢谢阿列克谢的回答。设置队列容量使其按预期运行,但现在我遇到了新问题。

后台任务量变化很大。大部分时间为 0,但短时间内最多可以执行 50 个并发任务。处理这个问题的有效方法是什么?请记住,大多数后台任务都是短期的 (< 1s),但也有一些长期任务 (> 1min)。

如果我这样设置我的线程池:

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

我很可能会在使用高峰时遇到 RejectedExecutionException。但是,如果我这样设置线程池:

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

然后将永远不会添加新的工作线程,因为队列不会达到最大值。

CPU 至少有 4 个内核,所以在我看来这会很浪费。而且大多数时候根本没有任何后台任务(80% 的正常运行时间),所以在我看来保持一个固定的线程池也是一种浪费。

ThreadPoolExecutor Javadoc 说:

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

您的 LinkedBlockingQueue 永远不会满,因为它没有元素数量的上限。将 new LinkedBlockingQueue() 更改为 new LinkedBlockingQueue(10) 即可解决该问题。