ThreadPoolExecutor
继承了submit(Callable<T> task)
方法
ThreadPoolExecutor
的构造函数接受实例BlockingQueue<Runnable>
。此阻止队列只能保留Runnable
个实例
ThreadPoolExecutor
构造函数的Javadoc说:
用于在执行任务之前保留任务的队列。此队列将仅保存execute方法提交的Runnable任务。
所以,我的问题是:通过submit(Callable<T> task)
提交的任务如何排队?
答案 0 :(得分:0)
使用Runnable
将其包裹在RunnableFuture
(特别是newTaskFor(Callable)
)中。请参阅source code。
答案 1 :(得分:0)
您可以在queuing section of the ThreadPoolExecutor
documentation中找到解释:
<强>队列强>
任何BlockingQueue都可用于转移和保留提交的任务。此队列的使用与池大小调整相互作用:
- 如果运行的corePoolSize线程少于,则执行程序总是更喜欢添加新线程而不是排队。
- 如果corePoolSize或更多线程正在运行,则Executor总是更喜欢排队请求而不是添加新线程。
- 如果请求无法排队,则会创建一个新线程,除非这会超过maximumPoolSize,在这种情况下,该任务将被拒绝。
排队有三种常规策略:
直接切换。工作队列的一个很好的默认选择是SynchronousQueue,它将任务交给线程而不另外保存它们。在这里,如果没有线程立即可用于运行它,则尝试对任务进行排队将失败,因此将构造新线程。此策略在处理可能具有内部依赖性的请求集时避免了锁定。直接切换通常需要无限制的maximumPoolSizes以避免拒绝新提交的任务。这反过来承认,当命令继续平均到达的速度超过可以处理的速度时,无限制线程增长的可能性。
无界队列。使用无界队列(例如,没有预定义容量的LinkedBlockingQueue)将导致新任务在所有corePoolSize线程忙时在队列中等待。因此,只会创建corePoolSize线程。 (并且maximumPoolSize的值因此没有任何影响。)当每个任务完全独立于其他任务时,这可能是适当的,因此任务不会影响彼此的执行;例如,在网页服务器中。虽然这种排队方式可以有助于平滑瞬态突发请求,但它承认,当命令继续平均到达的速度超过可以处理的速度时,无限制的工作队列增长的可能性。
- 醇>
有界队列。有限队列(例如,ArrayBlockingQueue)在与有限maximumPoolSizes一起使用时有助于防止资源耗尽,但可能更难以调整和控制。队列大小和最大池大小可以相互交换:使用大型队列和小型池最小化CPU使用率,OS资源和上下文切换开销,但可能导致人为的低吞吐量。如果任务经常阻塞(例如,如果它们是I / O绑定的),系统可能能够为您提供比您允许的更多线程的时间。使用小队列通常需要更大的池大小,这会使CPU更加繁忙,但可能会遇到不可接受的调度开销,这也会降低吞吐量。
可以在Executors
类中找到一些示例,它提供了创建多种ThreadPoolExecutor
类型的方法。
答案 2 :(得分:0)
使用带有提交(Callable)的有界队列是一件痛苦的事情,因为即使使用BlockingQueue也没有默认的方法来阻止它(我知道)。
可以帮助的一件事就是从提交中捕获RejectedExecutionException,然后等待再试一次。如果您的应用程序应阻止提交,直到阻塞队列中的容量可用,这将是合适的。例如,换行:
futures.add(executor.submit(callable));
像这样:
boolean submitted = false;
while(!submitted) {
try {
futures.add(executor.submit(callable));
submitted = true;
} catch(RejectedExecutionException e) {
try {
Thread.sleep(1000);
} catch(InterruptedException e2) {
throw new RuntimeException("Interrupted", e2);
}
}
}
我希望有所帮助。
答案 3 :(得分:0)
不需要任何包装。您可以通过 Executors 或直接作为新的 ThreadPoolExecutor 来创建 ExecutorService 。使用 submit(Callable) 方法,ThreadPoolExceutor 将为您包装 Callable 和 Runnable。 请注意,如果您使用拒绝处理程序,请记住您将获得包含您的 Callable 的包装器对象 FutureTask
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor){
FutureTask ft= (FutureTask)r;
}