【发布时间】:2017-11-07 11:58:52
【问题描述】:
每个人。
我对使用线程池有误解。实际结果与该类的 API 描述不同。当我在线程池中使用LinkedBlockedQueue 时,它不重用线程,线程池等待构造函数中设置的 KeepAliveTime,然后终止该线程并创建一个新线程。当我将 KeepAliveTime 设置为较小时,例如 1 秒或更短,它会删除线程并重新创建它,但如果我设置一分钟,则不会创建新线程,因为 MaxPoolSize 不允许它并且队列已经满,因此所有任务都被拒绝,但是keepAliveTime 设置为分钟的线程这次什么都不做。我很新,不明白为什么它不重用这些线程。在keepTimeAlive 到期后,它会杀死这些线程,如果队列已满,它会创建一个新线程。为什么它会这样工作?据我从 API 了解,如果线程在 keepAliveTime 期间空闲,则必须重用它。当我使用SynchronousQueue 时,它会重用线程,而不是LinkedBlockingQueue。
public class Main {
private volatile int remainingTasksCount;
private volatile static ThreadPoolExecutor consumer = new ThreadPoolExecutor(1, 2, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(3));
private static Runnable task = () -> {
System.out.println(String.format("consumer %s, id %s, size %s, active count %s, queue %s",
Thread.currentThread().getName(), Thread.currentThread().getId(),
consumer.getPoolSize(), consumer.getActiveCount(), 3-consumer.getQueue().remainingCapacity()));
String s = new String();
synchronized (s) {
try {
s.wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
public static void main(String[] args) throws IOException {
try {
new Thread(() -> {
while (true) {
try {
for (int i = 0; i < 5; i++) {
consumer.submit(task);
}
System.out.println("PUSH TASKS");
synchronized (Thread.currentThread()) {
Thread.currentThread().wait(10000);
}
} catch (Throwable th) {
System.out.println(th);
}
}
}).start();
} catch (Throwable th) {
System.out.println(th);
}
}
输出
PUSH TASKS
consumer pool-1-thread-1, id 15, size 2, active count 2, queue 3
consumer pool-1-thread-2, id 16, size 2, active count 2, queue 3
consumer pool-1-thread-2, id 16, size 2, active count 2, queue 1
consumer pool-1-thread-1, id 15, size 2, active count 1, queue 2
consumer pool-1-thread-1, id 15, size 2, active count 1, queue 0
Disconnected from the target VM, address: '127.0.0.1:64434', transport: 'socket'
Process finished with exit code 1
但是下次生产者提交任务时,我得到RejectedExecutionException
如果我将keepAliveTime 更改为1 Second。一切运行良好,但创建
新线程。
PUSH TASKS
consumer pool-1-thread-2, id 16, size 2, active count 2, queue 3
consumer pool-1-thread-1, id 15, size 2, active count 2, queue 3
consumer pool-1-thread-2, id 16, size 2, active count 2, queue 2
consumer pool-1-thread-1, id 15, size 2, active count 2, queue 1
consumer pool-1-thread-2, id 16, size 2, active count 1, queue 0
PUSH TASKS
consumer pool-1-thread-3, id 17, size 2, active count 2, queue 3
consumer pool-1-thread-2, id 16, size 2, active count 2, queue 2
consumer pool-1-thread-3, id 17, size 2, active count 2, queue 1
consumer pool-1-thread-2, id 16, size 2, active count 2, queue 1
consumer pool-1-thread-3, id 17, size 2, active count 1, queue 0
consumer pool-1-thread-3, id 17, size 1, active count 1, queue 2
PUSH TASKS
consumer pool-1-thread-4, id 18, size 2, active count 2, queue 3
consumer pool-1-thread-3, id 17, size 2, active count 2, queue 1
consumer pool-1-thread-4, id 18, size 2, active count 2, queue 1
consumer pool-1-thread-3, id 17, size 2, active count 1, queue 0
PUSH TASKS
consumer pool-1-thread-3, id 17, size 2, active count 2, queue 2
consumer pool-1-thread-5, id 19, size 2, active count 2, queue 3
consumer pool-1-thread-3, id 17, size 2, active count 2, queue 1
consumer pool-1-thread-5, id 19, size 2, active count 2, queue 1
consumer pool-1-thread-3, id 17, size 2, active count 1, queue 0
如果有人能解释我的错误,或者我错过了什么基本原则,我会很高兴
【问题讨论】:
-
TL;DR -
Executors.newCachedThreadPool()怎么样? -
这就是我写的问题,SynchronousQueue 重用线程,但 LinkedBlockingQueue 不是(API 说任何blockingQueue 接口实现者重用),它创建的线程与您的任务一样多。 public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue
()); } -
您不应该管理线程池使用的队列。这就是问题所在。如果您使用@rkosegi 建议的内容,则队列由
ExecutorService管理。如果您尝试限制活动线程,请使用Executors.newFixedThreadPool(15)。这将只允许一次执行 15 个线程,但允许您将任意数量的作业排队。 -
你在哪里看到我管理队列?每当我的程序执行时,我都不需要 15 个线程。它将每天加载 2-3 次。但这将是巨大的负担。所以我想动态增加线程数。我想,我可以制作更多的 corePoolSize 值和 allowCoreThreadTimeOut(true)。所以当线程空闲时它会减少线程数。当提交新任务并且线程池大小
标签: java multithreading threadpool