我是这个主题的新手......我正在使用用 Executors.newFixedThreadPool( 10 ) 创建的 ThreadPoolExecutor ,在池已满后,我开始收到 RejectedExecutionException 。有没有办法“强制”执行者将新任务置于“等待”状态,而不是在池被释放时拒绝它并启动它?
谢谢
我是这个主题的新手......我正在使用用 Executors.newFixedThreadPool( 10 ) 创建的 ThreadPoolExecutor ,在池已满后,我开始收到 RejectedExecutionException 。有没有办法“强制”执行者将新任务置于“等待”状态,而不是在池被释放时拒绝它并启动它?
谢谢
如果您使用Executors.newFixedThreadPool(10);
它将任务排队,它们会等待线程准备好。
这种方法是
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
如您所见,使用的队列是无限的(这本身可能是一个问题),但这意味着队列永远不会填满,您也永远不会被拒绝。
顺便说一句:如果您有 CPU 密集型任务,则最佳线程数可以是
int processors = Runtime.getRuntime().availableProcessors();
ExecutorService es = Executors.newFixedThreadPool(processors);
一个可以说明情况的测试类
public static void main(String... args) {
ExecutorService es = Executors.newFixedThreadPool(2);
for (int i = 0; i < 1000 * 1000; i++)
es.submit(new SleepOneSecond());
System.out.println("Queue length " + ((ThreadPoolExecutor) es).getQueue().size());
es.shutdown();
System.out.println("After shutdown");
try {
es.submit(new SleepOneSecond());
} catch (Exception e) {
e.printStackTrace(System.out);
}
}
static class SleepOneSecond implements Callable<Void> {
@Override
public Void call() throws Exception {
Thread.sleep(1000);
return null;
}
}
印刷
Queue length 999998
After shutdown
java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@e026161 rejected from java.util.concurrent.ThreadPoolExecutor@3e472e76[Shutting down, pool size = 2, active threads = 2, queued tasks = 999998, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2013)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:816)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1337)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:132)
at Main.main(Main.java:17)
很有可能一个线程调用exit
,它设置mStopped
为 false 并关闭执行程序,但是:
while (!mStopped)
循环中间并尝试将任务提交给已被关闭的执行程序exit
while
因为所做的更改mStopped
不可见(您不使用任何形式的围绕该标志的同步)。我会建议:
mStopped
挥发性基于之前的建议,您可以使用阻塞队列来构造一个固定大小的ThreadPoolExecutor
。如果您随后提供自己的RejectedExecutionHandler
将任务添加到阻塞队列中,它将按照描述的方式运行。
这是一个如何构建这样一个执行器的示例:
int corePoolSize = 10;
int maximumPoolSize = 10;
int keepAliveTime = 0;
int maxWaitingTasks = 10;
ThreadPoolExecutor blockingThreadPoolExecutor = new ThreadPoolExecutor(
corePoolSize, maximumPoolSize,
keepAliveTime, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(maxWaitingTasks),
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
executor.getQueue().put(r);
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while submitting task", e);
}
}
});
如果我理解正确,您的 ThreadPool 使用固定数量的线程创建,但您可能有更多任务要提交到线程池。我会根据请求计算 keepAliveTime 并动态设置它。这样你就不会有 RejectedExecutionException。
例如
long keepAliveTime = ((applications.size() * 60) / FIXED_NUM_OF_THREADS) * 1000; threadPoolExecutor.setKeepAliveTime(keepAliveTime, TimeUnit.MILLISECONDS);
其中应用程序是任务的集合,每次都可能不同。
如果您知道任务所需的平均时间,那应该可以解决您的问题。