8

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

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

THREAD_POOL = Executors.newCachedThreadPool();

但如果它不是实时的,我希望能够控制我的线程池的大小。为此,我正在考虑 2 个选项,但我并不真正了解其中的区别,以及哪一个会表现得更好。

选项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?任何帮助,将不胜感激。

4

1 回答 1

14

查看源代码你会意识到:

Executors.newFixedThreadPool(threadPoolSize);

相当于:_

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

由于它不提供显式RejectedExecutionHandler,因此使用默认值AbortPolicyRejectedExecutionException一旦队列已满,它基本上就会抛出。但是队列是无限的,所以它永远不会被填满。因此,这个执行器接受无限任务。

您的声明要复杂得多,而且完全不同:

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

  • 我不明白你RejectedExecutionHandler在做什么。如果池发现它不能再将任何可运行对象放入队列,它会调用您的处理程序。在此处理程序中,您...尝试再次将其Runnable放入队列中(这将99% 的案例都失败了堵塞)。最后你吞下了异常。似乎ThreadPoolExecutor.DiscardPolicy是你所追求的。

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

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

1 - 假设 2^31 是无穷大

于 2013-01-11T20:53:37.710 回答