使用Executors服务在Java中创建固定大小线程池的最佳方法 [英] Optimal way of creating a fixed size thread pool in Java using the Executors service

查看:437
本文介绍了使用Executors服务在Java中创建固定大小线程池的最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using the Executors framework in Java to create thread pools for a multi-threaded application, and I have a question related to performance.

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

I have an application which can work in realtime or non-realtime mode. In case it's realtime, I'm simply using the following:

THREAD_POOL = Executors.newCachedThreadPool();

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

But in case it's not realtime, I want the ability to control the size of my thread pool. To do this, I'm thinking about 2 options, but I don't really understand the difference, and which one would perform better.

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

Option 1 is to use the simple way:

THREAD_POOL = Executors.newFixedThreadPool(threadPoolSize);

选项2是创建我自己的 ThreadPoolExecutor 像这样:

Option 2 is to create my own ThreadPoolExecutor like this:

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

I would like to understand what is the advantage of using the more complex option 2, and also if I should use another data structure than LinkedBlockingQueue? Any help would be appreciated.

推荐答案

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

Looking at the source code you'll realize that:

Executors.newFixedThreadPool(threadPoolSize);

等效

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

因为它没有提供明确的 RejectedExecutionHandler ,使用默认 AbortPolicy 。一旦队列满了,它基本上会抛出 RejectedExecutionException 。但是队列是无限的,因此永远不会满员。因此,这个执行者接受inifnite 1 的任务数。

Since it doesn't provide explicit RejectedExecutionHandler, default AbortPolicy is used. It basically throws RejectedExecutionException once the queue is full. But the queue is unbounded, so it will never be full. Thus this executor accepts inifnite1 number of tasks.

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

Your declaration is much more complex and quite different:


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

  • new LinkedBlockingQueue<Runnable>(10000) will cause the thread pool to discard tasks if more than 10000 are awaiting.

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

I don't understand what your RejectedExecutionHandler is doing. If the pool discovers it cannot put any more runnables to the queue it calls your handler. In this handler you... try to put that Runnable into the queue again (which will fail in like 99% of the cases block). Finally you swallow the exception. Seems like ThreadPoolExecutor.DiscardPolicy is what you are after.

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

Looking at your comments below seems like you are trying to block or somehow throttle clients if tasks queue is too large. I don't think blocking inside RejectedExecutionHandler is a good idea. Instead consider CallerRunsPolicy rejection policy. Not entirely the same, but close enough.

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

To wrap up: if you want to limit the number of pending tasks, your approach is almost good. If you want to limit the number of concurrent threads, the first one-liner is enough.

1 - 假设2 ^ 31是无穷大

这篇关于使用Executors服务在Java中创建固定大小线程池的最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆