线程池不调整大小
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)
即可解决该问题。
我想创建一个缓存线程池,但它充当固定线程池。目前我有这个代码:
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)
即可解决该问题。