Java Executors.newCachedThreadPool()与Executors.newFixedThreadPool()的比较

Java Executors.newCachedThreadPool()与Executors.newFixedThreadPool()的比较,java,multithreading,concurrency,executorservice,threadpoolexecutor,Java,Multithreading,Concurrency,Executorservice,Threadpoolexecutor,对 我什么时候应该使用其中一种?在资源利用方面,哪种策略更好?我认为文档很好地解释了这两种功能的区别和用法: 创建重用线程的线程池 固定数量的线程关闭 共享的无界队列。无论如何 在这一点上,线程最多将 积极处理任务。如果 其他任务将在以下情况下提交: 所有线程都处于活动状态,它们将等待 在队列中,直到找到一个线程 可用。如果任何线程终止 由于执行过程中的故障 在关机之前,需要一个新的 如果需要执行,它的位置 后续任务。螺纹 池将一直存在,直到显式 关闭 创建创建新线程的线程池 线程,但将重复


我什么时候应该使用其中一种?在资源利用方面,哪种策略更好?

我认为文档很好地解释了这两种功能的区别和用法:

创建重用线程的线程池 固定数量的线程关闭 共享的无界队列。无论如何 在这一点上,线程最多将 积极处理任务。如果 其他任务将在以下情况下提交: 所有线程都处于活动状态,它们将等待 在队列中,直到找到一个线程 可用。如果任何线程终止 由于执行过程中的故障 在关机之前,需要一个新的 如果需要执行,它的位置 后续任务。螺纹 池将一直存在,直到显式 关闭

创建创建新线程的线程池 线程,但将重复使用 以前构造的线程 它们是可用的。这些游泳池将 通常可以提高 执行许多短命程序的程序 异步任务。执行的调用 将重用以前构建的 线程(如果可用)。如果不存在 线程可用,将创建一个新线程 将被创建并添加到池中。 尚未用于此操作的线程 60秒结束,然后 从缓存中删除。因此,一个水池 闲置足够长的时间将 不消耗任何资源。注意 具有相似属性但 不同的细节(例如, 可以创建超时参数) 使用ThreadPoolExecutor构造函数

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


因此,资源消耗将在很大程度上取决于形势。例如,如果您有大量长时间运行的任务,我建议使用
FixedThreadPool
。至于
CachedThreadPool
,文档说“这些池通常会提高执行许多短期异步任务的程序的性能”。

我认为文档很好地解释了这两个函数的区别和用法:

创建重用线程的线程池 固定数量的线程关闭 共享的无界队列。无论如何 在这一点上,线程最多将 积极处理任务。如果 其他任务将在以下情况下提交: 所有线程都处于活动状态,它们将等待 在队列中,直到找到一个线程 可用。如果任何线程终止 由于执行过程中的故障 在关机之前,需要一个新的 如果需要执行,它的位置 后续任务。螺纹 池将一直存在,直到显式 关闭

创建创建新线程的线程池 线程,但将重复使用 以前构造的线程 它们是可用的。这些游泳池将 通常可以提高 执行许多短命程序的程序 异步任务。执行的调用 将重用以前构建的 线程(如果可用)。如果不存在 线程可用,将创建一个新线程 将被创建并添加到池中。 尚未用于此操作的线程 60秒结束,然后 从缓存中删除。因此,一个水池 闲置足够长的时间将 不消耗任何资源。注意 具有相似属性但 不同的细节(例如, 可以创建超时参数) 使用ThreadPoolExecutor构造函数

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


因此,资源消耗将在很大程度上取决于形势。例如,如果您有大量长时间运行的任务,我建议使用
FixedThreadPool
。至于
CachedThreadPool
,文档中说“这些池通常会提高执行许多短期异步任务的程序的性能”。

只有当您有Javadoc中所述的短期异步任务时,如果您提交的任务需要更长的处理时间,则必须使用newCachedThreadPool,最终会创建太多线程。如果以更快的速度将长时间运行的任务提交到newCachedThreadPool(),则可能会达到100%的CPU

只有当您具有Javadoc中所述的短期异步任务时,才必须使用newCachedThreadPool,如果您提交的任务需要较长的处理时间,那么最终将创建太多线程。如果以更快的速度将长时间运行的任务提交到newCachedThreadPool(),则可能会达到100%的CPU

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

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

  • 它是无限的,这意味着您只需向服务中注入更多工作(DoS攻击),就为任何人打开了破坏JVM的大门。线程消耗了不可忽略的内存量,并且根据其正在进行的工作增加了内存消耗,因此以这种方式很容易推翻服务器(除非您有其他断路器)

  • 由于执行者前面有一个
    SynchronousQueue
    ,这意味着在任务给定者和线程池之间有一个直接的切换,这一事实加剧了无界问题。如果所有现有线程都很忙,则每个新任务将创建一个新线程。对于服务器代码来说,这通常是一种糟糕的策略。当CPU饱和时,现有任务需要更长的时间才能完成。然而,更多的任务被提交,更多的线程被创建,
    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>());
    }
    
    ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, 
    TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
    RejectedExecutionHandler handler)
    
    +-----------+-----------+-------------------+---------------------------------+ | Pool Type | Core Size | Maximum Size | Queuing Strategy | +-----------+-----------+-------------------+---------------------------------+ | Fixed | n (fixed) | n (fixed) | Unbounded `LinkedBlockingQueue` | +-----------+-----------+-------------------+---------------------------------+ | Cached | 0 | Integer.MAX_VALUE | `SynchronousQueue` | +-----------+-----------+-------------------+---------------------------------+