java中四种线程池及poolSize、corePoolSize、maximumPoolSize

简介: ThreadPoolExecutor重要参数

ThreadPoolExecutor重要参数


ThreadPoolExecutor有几个重要的成员变量:keepAliveTimeallowCoreThreadTimeOutpoolSizecorePoolSizemaximumPoolSize。下面分别介绍一下:

  • corePoolSize:线程池的基本大小。下面会解释什么是基本大小。
  • maximumPoolSize:线程池中允许的最大线程数。
    注意还有一个largestPoolSize,记录了曾经出现的最大线程个数。因为setMaximumPoolSize()可以改变最大线程数。
  • poolSize:线程池中当前线程的数量。
  • allowCoreThreadTimeOut:是否允许核心线程超时退出。
    如果该值为false,且poolSize<=corePoolSize,线程池都会保证这些核心线程处于存活状态,不会超时退出。
    如果为true,则不论poolSize的大小,都允许超时退出。
    如果poolSize>corePoolSize,则该参数不论true还是false,都允许超时退出。
    相关判断如下:


(poolSize > corePoolSize || allowCoreThreadTimeOut)
复制代码


  • keepAliveTime: 如果一个线程处在空闲状态的时间超过了该属性值,就会因为超时而退出。是否允许超时退出则取决于上面的逻辑。


poolSize、corePoolSize、maximumPoolSize


那么poolSizecorePoolSizemaximumPoolSize三者的关系是如何的呢?

当新提交一个任务时:

  1. 如果poolSize<corePoolSize,新增加一个线程处理新的任务。
  2. 如果poolSize=corePoolSize,新任务会被放入阻塞队列等待。
  3. 如果阻塞队列的容量达到上限,且这时poolSize<maximumPoolSize,新增线程来处理任务。
  4. 如果阻塞队列满了,且poolSize=maximumPoolSize,那么线程池已经达到极限,会根据饱和策略RejectedExecutionHandler拒绝新的任务。

所以通过上面的描述可知corePoolSize<=maximumPoolSizepoolSize<=maximumPoolSize;而poolSizecorePoolSize无法比较,poolSize是有可能比corePoolSize大的。


四种线程池


Executors提供四种线程池:

  • newCachedThreadPool :缓存线程池,如果线程池长度超过处理需要,可回收空闲线程,若无可回收,则新建线程。
  • newFixedThreadPool : 定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  • newScheduledThreadPool : 计划线程池,支持定时及周期性任务执行。
  • newSingleThreadExecutor :单线程线程池,用唯一的线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

那么corePoolSize、maximumPoolSize在上面四种线程池中如何设定的?

通过几个newXXX函数的源码就可以知道,源码如下:


newFixedThreadPool


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

定长线程池的corePoolSizemaximumPoolSize相同。都是设定值。


newCachedThreadPool


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


缓存线程池corePoolSize为0,maximumPoolSize则是int最大值。


newSingleThreadExecutor


public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
复制代码


单线程线程池corePoolSizemaximumPoolSize都是1。


newScheduledThreadPool


public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}
复制代码


计划线程池用的是ThreadPoolExecutor的一个子类,可以看到corePoolSize是定义的,而maximumPoolSize则是int最大值。

注意这里的corePoolSizemaximumPoolSize不是最终的,因为可以通过setCorePoolSizesetMaximumPoolSize()改变。


阻塞队列


上面提到阻塞队列的饱和,那么这个饱和值是多少呢?

通过上面的代码可以看到

(1) 定长线程池和单线程线程都使用LinkedBlockingQueue,而LinkedBlockingQueue默认的大小是int的最大值,如下:


public LinkedBlockingQueue() {
    this(Integer.MAX_VALUE);
}
复制代码


(2)计划线程池使用的是DelayedWordQueue,它默认大小是16,但是可以动态增长,最大值则是int的最大值,如下:

private static final int INITIAL_CAPACITY = 16;
private RunnableScheduledFuture<?>[] queue =
    new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
private void grow() {
    int oldCapacity = queue.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); // grow 50%
    if (newCapacity < 0) // overflow
        newCapacity = Integer.MAX_VALUE;
    queue = Arrays.copyOf(queue, newCapacity);
}
复制代码


(3)缓存线程池使用的则是SynchronousQueue,这个比较特殊没有所谓的饱和值,而且前面也看到了缓存线程池的corePoolSize默认是0。所以它新建一个线程与 SynchronousQueue的机制有关, 这里不展开说了,有兴趣的可以研究一下这个类。


目录
相关文章
|
22小时前
|
Java 数据处理 调度
Java多线程编程入门指南
Java多线程编程入门指南
|
1天前
|
监控 安全 算法
如何有效地处理Java中的多线程
如何有效地处理Java中的多线程
|
2天前
|
Java
解析Java线程池:参数详解与执行流程
解析Java线程池:参数详解与执行流程
6 1
|
2天前
|
Java 调度
Java多线程编程与并发控制策略
Java多线程编程与并发控制策略
|
2天前
|
安全 算法 Java
java多线程面试题2019整理
java多线程面试题2019整理
|
2天前
|
安全 Java 开发者
Java并发编程:理解并发与多线程
在当今软件开发领域,Java作为一种广泛应用的编程语言,其并发编程能力显得尤为重要。本文将深入探讨Java中的并发编程概念,包括多线程基础、线程安全、并发工具类等内容,帮助开发者更好地理解和应用Java中的并发特性。
6 1
|
3天前
|
Java
java线程池执行任务(一次任务、固定间隔时间任务等)
java线程池执行任务(一次任务、固定间隔时间任务等)
6 1
|
3天前
|
监控 Java 调度
Java并发编程:深入理解线程池
【6月更文挑战第26天】在Java并发编程的世界中,线程池是提升应用性能、优化资源管理的关键组件。本文将深入探讨线程池的内部机制,从核心概念到实际应用,揭示如何有效利用线程池来处理并发任务,同时避免常见的陷阱和错误实践。通过实例分析,我们将了解线程池配置的策略和对性能的影响,以及如何监控和维护线程池的健康状况。
7 1
|
1天前
|
安全 Java 开发者
Java并发编程中的线程安全策略
在现代软件开发中,Java语言的并发编程特性使得多线程应用成为可能。然而,随着线程数量的增加,如何确保数据的一致性和系统的稳定性成为开发者面临的挑战。本文将探讨Java并发编程中实现线程安全的几种策略,包括同步机制、volatile关键字的使用、以及java.util.concurrent包提供的工具类,旨在为Java开发者提供一系列实用的方法来应对并发问题。
8 0
|
1天前
|
监控 Java UED
Java并发编程:深入理解线程池的设计与应用
本文旨在通过数据导向和科学严谨的方式,深入探讨Java并发编程中的关键组件——线程池。文章首先概述了线程池的基本概念与重要性,随后详细解读了线程池的核心参数及其对性能的影响,并通过实验数据支持分析结果。此外,文中还将介绍如何根据不同的应用场景选择或设计合适的线程池,以及如何避免常见的并发问题。最后,通过案例研究,展示线程池在实际应用中的优化效果,为开发人员提供实践指导。
7 0