Java中的ThreadPoolExecutor线程池原理细节解析

 更新时间:2023年12月27日 10:35:08   作者:笑我归无处  
这篇文章主要介绍了Java中的ThreadPoolExecutor线程池原理细节解析,ThreadPoolExecutor是一个线程池,最多可使用7个参数来控制线程池的生成,使用线程池可以避免创建和销毁线程的资源损耗,提高响应速度,并且可以管理线程池中线程的数量和状态等等,需要的朋友可以参考下

一、什么是ThreadPoolExecutor

ThreadPoolExecutor是一个线程池,最多可使用7个参数来控制线程池的生成。 使用线程池可以避免创建和销毁线程的资源损耗,提高响应速度,并且可以管理线程池中线程的数量和状态等等。 阿里巴巴手册中也推荐使用该线程池,因为Executors创建缓存线程池时,最大线程数是Integer.MAX_VALUE,可能导致堆栈溢出。而且使用ThreadPoolExecutor创建线程池可以让开发者更好理解线程池原理。

二、使用线程池的优点

1.减少系统资源消耗

无须重复创建和销毁线程,减少了线程创建和销毁造成的资源消耗。

2.提高响应速度

创建好的线程会驻留在线程池中,无需创建新线程执行任务,因而提高了响应速度。

3.提高了线程的可管理性。

线程池可以控制线程的数量,可以选择拒绝策略,可以监控和管理线程的状态,控制并发量等等。 这些都是自己创建线程难以做到的。

三、线程池原理

3.1 线程池的7个参数

1)corePoolSize 核心线程数

线程池常驻线程数量

2)maximumPoolSize 最大线程数

最大可存在的线程数量

3)keepAliveTime 非核心线程的存活时间

非核心线程空闲时,可以停留的时间

4)unit 存活时间的单位

非核心线程空闲时,可以停留的时间的单位

5)workQueue 阻塞队列

线程都在使用中时,可以将任务保存在阻塞队列中,可以设置队列的长度。

6)threadFactory 线程创建工厂

可以选择创建线程的工厂

7)handler 拒绝策略

当线程池无法存放更多任务时,处理这些过多的任务的策略

3.2 线程池执行任务的流程

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    //判断工作线程数是否小于核心线程数
    if (workerCountOf(c) < corePoolSize) {
    	//是,创建一个新线程
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    //否,将任务尝试添加到阻塞队列中,如果队列满了则会添加失败。
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        //判断线程池状态是否在运行中,不在运行中时,删除该任务
        if (! isRunning(recheck) && remove(command))
        	//不在运行中时,执行拒绝策略
            reject(command);
        //判断工作线程数是否为0
        else if (workerCountOf(recheck) == 0)
        	//为0的场合,尝试创建新线程
            addWorker(null, false);
    }
    //添加失败的场合,尝试创建一个新线程
    else if (!addWorker(command, false))
    	//如果添加失败,执行拒绝策略
        reject(command);
}
  1. 当执行一个任务时,首先会判断工作线程数是否小于核心线程数。
    • 如果小于核心线程数,则创建一个新线程来执行该任务。执行完毕。
  2. 如果大于核心线程数,则尝试将任务放入阻塞队列中。
    • 如果成功放入阻塞队列,待有空闲的线程时,空闲线程会从阻塞队列中获取任务并执行。执行完毕。
  3. 如果放入失败,表示阻塞队列已满,此时会尝试创建一个新线程来执行该任务。
    • 如果当前线程数小于最大线程数,则会创建新线程来执行该任务。执行完毕。
    • 如果工作线程数等于最大线程数,则不会创建新线程,尝试创建失败。此时会执行拒绝策略。执行完毕。

四、Executors提供的常用线程池

4.1 Executors.newFixedThreadPool

一个固定数量的线程池,可以通过传入的参数int nThreads来控制线程池的线程数量。(核心线程数和最大线程数相同)

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

4.2 Executors.newSingleThreadExecutor

一个线程数只有1的线程池。可以保证任务的顺序执行。

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

4.3 Executors.newCachedThreadPool

缓存线程池,新创建的线程会在该线程池中缓存60秒。可以提高短期异步任务的性能。 注意,最大线程数是Integer.MAX_VALUE,高并发的场合下,可能会创建大量线程。

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

4.4 Executors.newScheduledThreadPool

定时任务线程池,使用该线程池可以定时执行任务。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

到此这篇关于Java中的ThreadPoolExecutor线程池原理细节解析的文章就介绍到这了,更多相关ThreadPoolExecutor线程池原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot热部署设置方法详解

    SpringBoot热部署设置方法详解

    在实际开发中,每次修改代码就需要重启项目,重新部署,对于一个后端开发者来说,重启确实很难受。在java开发领域,热部署一直是一个难以解决的问题,目前java虚拟机只能实现方法体的热部署,对于整个类的结构修改,仍然需要重启项目
    2022-10-10
  • java取出list中某几个属性组成一个新集合的几种方式

    java取出list中某几个属性组成一个新集合的几种方式

    在Java开发中经常需要对List中的对象进行一些操作,例如对某个字段进行过滤、排序等,这篇文章主要给大家介绍了关于java取出list中某几个属性组成一个新集合的几种方式,需要的朋友可以参考下
    2024-03-03
  • MyBatis-Flex实现多表联查(自动映射)

    MyBatis-Flex实现多表联查(自动映射)

    我们可以轻松的使用 Mybaits-Flex 链接任何数据库,本文主要介绍了MyBatis-Flex实现多表联查(自动映射),具有一定的参考价值,感兴趣的可以了解一下
    2024-06-06
  • Java Lambda 表达式源码解析

    Java Lambda 表达式源码解析

    这篇文章主要介绍了Java Lambda在JVM中是如何实现的,感兴趣的小伙伴一起来了解了解
    2021-08-08
  • 使用lombok的@Data会导致栈溢出StackOverflowError问题

    使用lombok的@Data会导致栈溢出StackOverflowError问题

    这篇文章主要介绍了使用lombok的@Data会导致栈溢出StackOverflowError问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • Java实现自定义自旋锁代码实例

    Java实现自定义自旋锁代码实例

    这篇文章主要介绍了Java实现自定义自旋锁代码实例,Java自旋锁是一种线程同步机制,它允许线程在获取锁时不立即阻塞,而是通过循环不断尝试获取锁,直到成功获取为止,自旋锁适用于锁竞争激烈但持有锁的时间很短的情况,需要的朋友可以参考下
    2023-10-10
  • spring boot配置拦截器代码实例

    spring boot配置拦截器代码实例

    这篇文章主要介绍了spring boot配置拦截器代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • Spring Boot与前端配合与Idea配置部署操作过程

    Spring Boot与前端配合与Idea配置部署操作过程

    这篇文章主要介绍了Spring Boot与前端配合与Idea配置部署的操作过程,本文图文并茂给大家介绍的非常详细,需要的朋友可以参考下
    2018-02-02
  • Java中将bean放入Spring容器中的几种方式详解

    Java中将bean放入Spring容器中的几种方式详解

    这篇文章主要介绍了Java中将bean放入Spring容器中的几种方式详解,在Spring框架中,有多种方式可以将Bean(即对象)放入Spring容器中,今天我们就来详细说一下这几种方式,需要的朋友可以参考下
    2023-07-07
  • Java中数据转换及字符串的“+”操作方法

    Java中数据转换及字符串的“+”操作方法

    本文主要介绍了Java中的数据类型转换,包括隐式转换和强制转换,隐式转换通常用于将范围较小的数据类型转换为范围较大的数据类型,而强制转换则是将范围较大的数据类型转换为范围较小的数据类型,本文介绍Java中数据转换以及字符串的“+”操作,感兴趣的朋友一起看看吧
    2024-10-10

最新评论