使用Executors服务在Java中创建固定大小线程池的最佳方法

时间:2013-01-11 20:34:43

标签: java multithreading threadpool executorservice

我在Java中使用Executors框架为多线程应用程序创建线程池,我有一个与性能相关的问题。

我有一个可以在实时或非实时模式下工作的应用程序。如果它是实时的,我只是使用以下内容:

THREAD_POOL = Executors.newCachedThreadPool();

但是如果它不是实时的,我希望能够控制我的线程池的大小。 要做到这一点,我正在考虑两个选项,但我并不真正理解其中的差异,哪个会更好。

选项1是使用简单的方法:

THREAD_POOL = Executors.newFixedThreadPool(threadPoolSize);

选项2是创建我自己的ThreadPoolExecutor,如下所示:

RejectedExecutionHandler rejectHandler = new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
    try {
        executor.getQueue().put(r);
    } catch (Exception e) {}
}
};          
THREAD_POOL = new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(10000), rejectHandler);

我想了解使用更复杂的选项2的优势是什么,以及我是否应该使用除LinkedBlockingQueue以外的其他数据结构?任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:14)

查看源代码,您将意识到:

Executors.newFixedThreadPool(threadPoolSize);

等效到:

return new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 0L, MILLISECONDS,
                              new LinkedBlockingQueue<Runnable>());

由于它未提供显式RejectedExecutionHandler,因此使用默认AbortPolicy。一旦队列满了,它基本上会抛出RejectedExecutionException。但是队列是无限的,所以它永远不会满。因此,这个执行器接受inifnite 1 的任务数。

你的声明要复杂得多,而且差异很大:

    如果超过10000等待,
  • new LinkedBlockingQueue<Runnable>(10000)将导致线程池丢弃任务。

  • 我不明白你RejectedExecutionHandler在做什么。如果池发现它不能再将任何可运行的队列放入队列,则会调用您的处理程序。在这个处理程序中,你......尝试再次将Runnable放入队列中(这将使失败,如99%的情况块)。最后你吞下了这个例外。好像ThreadPoolExecutor.DiscardPolicy就是你所追求的。

    如果任务队列太大,查看下面的评论似乎是在试图阻止或以某种方式限制客户端。我不认为在RejectedExecutionHandler内阻挡是个好主意。而是考虑CallerRunsPolicy拒绝政策。不完全相同,但足够接近。

结束:如果你想限制待处理任务的数量,你的方法几乎是好的。如果你想限制并发线程的数量,第一个单线程就足够了。

1 - 假设2 ^ 31是无穷大