我可以 运行 线程池中的后台任务吗?
Can I run background tasks in a ThreadPool?
我有一个 ExecutorService
可以同时执行我的任务。这些任务中的大多数都是简单的操作,每个操作需要大约 300 毫秒才能完成。但是其中一些任务是后台处理队列,它们一直接收新的子任务并按顺序执行它们。只要有正常任务,这些后台任务就会保持活动状态运行。
ThreadPool 是通过 Executors
' 方法之一(目前还不知道是哪个)生成的,具有用户指定的线程数。我担心可能会发生以下情况:线程数少于后台队列数。在给定的时刻,所有后台队列都在工作,阻塞了 ExecutorService
的所有线程。因此不会启动任何正常任务,程序将永远挂起。
是否有可能发生这种情况,我该如何避免?我在想有没有可能打断后台任务,把地方留给正常的。
目标是限制我的应用程序中的线程数,因为 Google 说有很多线程不好,让它们大部分时间空闲也不好。
程序开始执行时,将在很短的时间内提交约 10000 个任务。大约需要 ~50 个后台任务队列,大部分时间将花费在等待后台作业上。
您可以拥有无限数量的线程,查看 cache thread pool
Creates a thread pool that creates new threads as needed, but will
reuse previously constructed threads when they are available. These
pools will typically improve the performance of programs that execute
many short-lived asynchronous tasks. Calls to execute will reuse
previously constructed threads if available. If no existing thread is
available, a new thread will be created and added to the pool. Threads
that have not been used for sixty seconds are terminated and removed
from the cache. Thus, a pool that remains idle for long enough will
not consume any resources. Note that pools with similar properties but
different details (for example, timeout parameters) may be created
using ThreadPoolExecutor constructors.
另一种选择是创建两个不同的池并为优先任务保留一个。
不要在同一个 ExecutorService
中混淆长 运行 任务和短 运行 任务。
使用两个不同的 ExecutorService
池大小合适的实例。即使您将具有长 运行 任务的后台线程的大小设置为 50,池的性能也不是最佳的,因为可用内核的数量(2 核、4 核、8 核等)不在该数量内。
我想创建两个单独的 ExecutorService
用 Runtime.getRuntime().availableProcessors()/2
;
初始化
查看以下帖子以了解更多详细信息以有效利用可用内核:
How to implement simple threading with a fixed number of worker threads
解决方案是当没有工作时后台任务停止而不是空闲,如果再次有足够的任务则重新启动。
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();
}
}
}
我有一个 ExecutorService
可以同时执行我的任务。这些任务中的大多数都是简单的操作,每个操作需要大约 300 毫秒才能完成。但是其中一些任务是后台处理队列,它们一直接收新的子任务并按顺序执行它们。只要有正常任务,这些后台任务就会保持活动状态运行。
ThreadPool 是通过 Executors
' 方法之一(目前还不知道是哪个)生成的,具有用户指定的线程数。我担心可能会发生以下情况:线程数少于后台队列数。在给定的时刻,所有后台队列都在工作,阻塞了 ExecutorService
的所有线程。因此不会启动任何正常任务,程序将永远挂起。
是否有可能发生这种情况,我该如何避免?我在想有没有可能打断后台任务,把地方留给正常的。
目标是限制我的应用程序中的线程数,因为 Google 说有很多线程不好,让它们大部分时间空闲也不好。
程序开始执行时,将在很短的时间内提交约 10000 个任务。大约需要 ~50 个后台任务队列,大部分时间将花费在等待后台作业上。
您可以拥有无限数量的线程,查看 cache thread pool
Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available. These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks. Calls to execute will reuse previously constructed threads if available. If no existing thread is available, a new thread will be created and added to the pool. Threads that have not been used for sixty seconds are terminated and removed from the cache. Thus, a pool that remains idle for long enough will not consume any resources. Note that pools with similar properties but different details (for example, timeout parameters) may be created using ThreadPoolExecutor constructors.
另一种选择是创建两个不同的池并为优先任务保留一个。
不要在同一个 ExecutorService
中混淆长 运行 任务和短 运行 任务。
使用两个不同的 ExecutorService
池大小合适的实例。即使您将具有长 运行 任务的后台线程的大小设置为 50,池的性能也不是最佳的,因为可用内核的数量(2 核、4 核、8 核等)不在该数量内。
我想创建两个单独的 ExecutorService
用 Runtime.getRuntime().availableProcessors()/2
;
查看以下帖子以了解更多详细信息以有效利用可用内核:
How to implement simple threading with a fixed number of worker threads
解决方案是当没有工作时后台任务停止而不是空闲,如果再次有足够的任务则重新启动。
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();
}
}
}