我有一个ExecutorService
来同时执行我的任务。大多数这些任务都是简单的操作,每个任务需要大约300毫秒。但是其中一些任务是后台处理队列,它们始终接收新的子任务并按顺序执行它们。只要正常任务正在运行,这些后台任务就会保持活动状态。
ThreadPool是通过一个Executors
'方法(不知道哪个)和用户指定的线程计数生成的。我担心以下情况可能会发生:线程少于后台队列。在给定时刻,所有后台队列都在工作,阻塞ExecutorService
的所有线程。因此,不会启动任何正常任务,程序将永远挂起。
是否有可能发生这种情况,我该如何避免呢?我正在考虑中断后台任务的可能性,让这个地方离开正常的地方。
我的目标是限制我的应用程序中的线程数量,因为谷歌表示有很多线程是坏的,并且大部分时间让它们闲置也很糟糕。
在程序执行开始时,将在很短的时间内提交约10000个任务。大约需要约50个后台任务队列,大部分时间都花在等待后台工作上。
答案 0 :(得分:2)
不要将长时间运行的任务与同一ExecutorService
中的短期运行任务混淆。
使用具有正确池大小的两个不同ExecutorService
个实例。即使您将具有长时间运行任务的后台线程的大小设置为50,池的性能也不是最佳的,因为可用核心数(2核,4核,8核等)不在该数量中。
我想创建两个单独的ExecutorService
初始化Runtime.getRuntime().availableProcessors()/2
;
请查看以下帖子,了解有效利用可用内核的更多详情:
How to implement simple threading with a fixed number of worker threads
答案 1 :(得分:1)
您可以拥有无限数量的主题,请查看cache thread pool
创建一个线程池,根据需要创建新线程,但是会 在先前构造的线程可用时重用它们。这些 池通常会提高执行程序的性能 许多短暂的异步任务。执行调用将重用 以前构造的线程(如果有)如果没有现有的线程 可用时,将创建一个新线程并将其添加到池中。主题 未使用60秒的任务将被终止并删除 从缓存。因此,一个长时间闲置的游泳池将会 不消耗任何资源。请注意具有相似属性的池 可以创建不同的细节(例如,超时参数) 使用ThreadPoolExecutor构造函数。
另一种选择是创建两个不同的池,并为优先级任务保留一个。
答案 2 :(得分:0)
解决方案是后台任务在没有工作时停止而不是空闲,如果有足够的任务就重新启动。
public class BackgroundQueue implements Runnable {
private final ExecutorService service;
private final Queue<Runnable> tasks = new ConcurrentLinkedQueue<>();
private final AtomicBoolean running = new AtomicBoolean(false);
private Future<?> future;
public BackgroundQueue(ExecutorService service) {
this.service = Objects.requireNonNull(service);
// Create a Future that immediately returns null
FutureTask f = new FutureTask<>(() -> null);
f.run();
future = f;
}
public void awaitQueueTermination() throws InterruptedException, ExecutionException {
do {
future.get();
} while (!tasks.isEmpty() || running.get());
}
public synchronized void submit(Runnable task) {
tasks.add(task);
if (running.compareAndSet(false, true))
future = service.submit(this);
}
@Override
public void run() {
while (!running.compareAndSet(tasks.isEmpty(), false)) {
tasks.remove().run();
}
}
}