我想创建一个缓存线程池,但它作为一个固定的线程池。目前,我有这样的代码:线程池不调整大小
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个并发任务。什么是处理这个问题的有效方法?请记住,大多数后台任务都是短暂的(< 1秒),但也有一些长期任务(> 1分钟)。
如果我把我的线程池像这样:
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%的正常运行时间),因此保留固定的线程池也是浪费的。
感谢您的理解。但是现在我得到了RejectedExecutionException(池大小= 10,活动线程= 10,排队任务= 10),因为队列被填满并且所有活动的线程都用完了。 –