回答

141

我觉得文档解释了这两个函数的区别和用法相当不错:

newFixedThreadPool

创建一个可重用 不受限制的队列工作线程 固定数量的线程池。在任何 点,最多nThreads线程将 是活动的处理任务。如果在 所有线程是活动 额外的任务提交,他们将等待 在队列中,直到一个线程是 可用。如果任何线程执行 之前关闭期间终止 由于故障,如果需要执行 后续任务新需要 它的位置。 池中的线程将一直存在,直到明确地关闭 。

newCachedThreadPool

创建一个可根据需要创建新 线程的线程池,但将重用 以前构造的线程时 它们是可用的。这些池将 通常提高 程序,执行许多短命 异步任务的性能。如果可用,调用执行 将重新使用先前构造的 线程。如果没有现有的 线程可用,则会创建一个新线程 并将其添加到池中。 终止60秒并未使用 的线程,并从缓存中删除 。因此,保持空闲时间足够长的池 将不消耗任何资源。需要注意的是 池具有类似性质的但 不同的细节(例如, 超时参数)可以被使用的ThreadPoolExecutor构造创建 。

在资源方面,newFixedThreadPool将保持所有线程运行,直到它们被明确终止。在newCachedThreadPool未使用60秒的线程被终止并从缓存中删除。

鉴于此,资源消耗将在形势非常依赖。例如,如果你有很多长时间运行的任务,我会建议FixedThreadPool。至于CachedThreadPool,文档说“这些池通常会提高执行许多短暂异步任务的程序的性能”。

+1

是的,我已经通过docs..the问题了被... fixedThreadPool是造成内存不足的错误@ 3个线程..作为cachedPool在内部只创建一个单线程..在增加堆大小 我得到相同的性能两个..我还有什么我失踪!! – hakish 2009-06-04 12:22:41

7

没错,Executors.newCachedThreadPool()对于服务于多个客户端和并发请求的服务器代码并不是一个好的选择。

为什么?基本上有两个(相关)与它的问题:

  1. 这是无界的,这意味着你打开大门,任何人通过简单地注入更多工作纳入服务(DoS攻击),以削弱你的JVM。线程消耗了不可忽视的内存量,并且还会因为正在进行的工作而增加内存消耗,所以这样很容易推倒服务器(除非有其他断路器)。

  2. Executor的前端是SynchronousQueue,这意味着task-giver和线程池之间有直接的切换,从而加剧了无限的问题。如果所有现有线程都忙碌,则每个新任务都将创建一个新线程。这通常是服务器代码的一个糟糕的策略。当CPU变得饱和时,现有任务需要更长时间才能完成。然而,更多的任务正在提交并创建更多的线程,因此任务需要更长,更长的时间才能完成。当CPU饱和时,更多线程肯定不是服务器需要的。

这里是我的建议:

使用固定大小的线程池Executors.newFixedThreadPool或线程组最大数量ThreadPoolExecutor.;

9

如果您在grepcode中看到代码,您会看到它们在内部调用ThreadPoolExecutor.并设置它们的属性。您可以创建一个更好地控制您的需求。

public static ExecutorService newFixedThreadPool(int nThreads) { 
    return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS, 
new LinkedBlockingQueue<Runnable>()); 
} 

public static ExecutorService newCachedThreadPool() { 
     return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 
             60L, TimeUnit.SECONDS, 
             new SynchronousQueue<Runnable>()); 
} 
5

如果你不担心赎回/的Runnable任务无界队列,你可以使用其中之一。正如bruno所建议的那样,我也更喜欢这两者之间的newFixedThreadPoolnewCachedThreadPool

ThreadPoolExecutor提供相比,无论newFixedThreadPoolnewCachedThreadPool

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, 
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, 
RejectedExecutionHandler handler) 

优势更加灵活的特点:

  1. 您对的BlockingQueue尺寸完全控制。它不像前两种选择那样没有界限。由于系统中出现意外动荡的待处理Callable/Runnable任务,因此我不会发生内存不足错误。

  2. 您可以自定义实现拒绝处理政策或使用的策略之一:

    1. 在默认ThreadPoolExecutor.AbortPolicy,处理程序时拒绝将抛出运行时RejectedExecutionException。

    2. ThreadPoolExecutor.CallerRunsPolicy中,调用自身执行的线程运行该任务。这提供了一个简单的反馈控制机制,可以减慢提交新任务的速度。

    3. ThreadPoolExecutor.DiscardPolicy中,无法执行的任务将被简单地删除。

    4. ThreadPoolExecutor.DiscardOldestPolicy,如果执行程序没有关闭,在工作队列头部的任务将被丢弃,然后执行重试(可再次失败,导致此重复。)

  3. 可以实现自定义线程工厂下面的用例:

    1. 要设置更具描述性的线程名
    2. 要设置线程进程的状态
    3. 要设置线程的优先级
39

只是为了完成其他的答案,我想引用有效的Java,第二版,由约书亚·布洛克,第10章,第68项:

“为特定应用程序选择执行程序服务可能会非常棘手。如果你正在写一个小程序,或轻负载的服务器,使用Executors.new- CachedThreadPool是一般是不错的选择,因为它要求任何配置一般是“做正确的事。”但是,一个缓存的线程池是不是一个好的选择为一个重载生产服务器

缓存的线程池提交的任务不排队,但立即被交给了执行的线程。 如果没有线程可用,则会创建一个新线程。如果一台服务器负载过重以至于所有的CPU都被充分利用,并且有更多的任务到达,那么将会创建更多的线程,这只会让事情变得更糟。

因此,在负载很重的生产服务器,你是用得多Executors.newFixedThreadPool,它给你一个游泳池有固定数量的线程,或直接使用的ThreadPoolExecutor类,为最大程度的控制更好。

相关问题