Java的线程池ThreadPoolExecutor及多种线程池实现详解

 更新时间:2024年01月11日 10:43:36   作者:好奇的7号  
这篇文章主要介绍了Java的线程池ThreadPoolExecutor及多种线程池实现详解,ThreadPoolExecutor 使用 int 的高 3 位来表示线程池状态,低 29 位表示线程数量,之所以将信息存储在一个变量中,是为了保证原子性,需要的朋友可以参考下

1、线程池状态含义

ThreadPoolExecutor 使用 int 的高 3 位来表示线程池状态,低 29 位表示线程数量,之所以将信息存储在一个变量中,是为了保证原子性。

具体的高三位与线程池状态如下,引用自网课的图片:

2、构造方法的参数、具体工作方式

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

对于以上变量,其含义如下:corePoolSize 核心线程数目 (最多保留的线程数)

  • maximumPoolSize 最大线程数目
  • keepAliveTime 生存时间
  • unit 生存时间的时间单位
  • workQueue 阻塞队列
  • threadFactory 线程工厂 - 可以为线程创建时起个好名字
  • handler 拒绝策略

具体解释:

1.核心线程数:是指在线程池中始终保持存活的线程数量。在线程池中,当有新的任务到达时,线程池会创建新的线程来处理任务,但是当任务处理完毕后,线程并不会立即销毁,而是被放置在线程池中等待下一个任务的到来。 当将allowCoreThreadTimeout设置为 true 时,核心线程也会超时回收,像这样:

executor.allowCoreThreadTimeOut(true); // 允许回收核心线程

2.最大线程数目:指核心线程数+非核心线程数的总数。例如设置核心为5,最大为10,那么非核心(救急)则为10-5=5个

3.生存时间:线程闲置超时时长。如果超过该时长,非核心线程就会被回收。如果将allowCoreThreadTimeout设置为 true 时,核心线程也会超时回收。

4.阻塞队列:如果核心线程都被占用没有空闲,此时又多来了新任务,则新来的任务会被加入阻塞队列阻塞等待。

5.拒绝策略:如果阻塞队列满了,继续来任务,那么就创建救急线程来执行新任务,但如果救急线程也不够(达到最大线程数),再来任务,因为线程池已经填满了到极限了,所以就要拒绝新来的任务了。jdk和各种框架有多种拒绝策略的实现:

  • AbortPolicy 让调用者抛出 RejectedExecutionException 异常,这是默认策略
  • CallerRunsPolicy 让调用者运行任务
  • DiscardPolicy 放弃本次任务
  • DiscardOldestPolicy 放弃队列中最早的任务,本任务取而代之
  • ActiveMQ 的实现,带超时等待(60s)尝试放入队列(较好)

3、线程池有哪些常用的实现方式

3.1 newFixedThreadPool

全是、多个核心线程不回收

fixed,即“固定的”,线程数固定,能够控制线程的最大并发数:

(1)源码中,其核心线程数和最大线程数都是nThreads,即相等,说明没有非核心线程

(2)阻塞队列是无界的,可以放任意数量的任务。

(3)核心线程不会自动回收,直到被明确打断:“The threads in the pool will exist until it is explicitly shutdown.”

public static ExecutorService newFixedThreadPool(int nThreads) {
     return new ThreadPoolExecutor(nThreads, nThreads,
     0L, TimeUnit.MILLISECONDS,
     new LinkedBlockingQueue<Runnable>());
}
//具体使用示例
//1.创建定长线程池对象,线程数量固定为3
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
//2. 创建Runnable线程对象以及执行的任务
Runnable task =new Runnable(){
  public void run() {
     System.out.println("执行任务啦");
  }
};
//3. 向线程池提交任务
fixedThreadPool.execute(task);

3.2newCachedThreadPool

全是非核心,定时回收

Cached,缓存,是说这种线程池的实现像缓存一样是可变的:

(1)核心线程数是 0, 最大线程数是 Integer.MAX_VALUE,线程的空闲生存时间是 60s,意味着:这种线程池内都是非核心线程、可以无限创建、定时60s回收。

(2)队列采用了 SynchronousQueue ,特点是,它没有容量,没有线程来取是放不进去的。

(3)适合场景:执行大量、耗时少的任务。

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

3.3newSingleThreadExecutor

就一个核心线程,不回收

Single,即单线程的线程池:只有 1 个核心线程,无非核心线程,执行后不会立即回收。 这样相当于顺序执行,不需要处理线程同步问题。

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

3.4newScheduledThreadPool

核心非核心都有,非核心定时回收

Scheduled即定时的:核心线程数量固定,非核心线程数量无限多但会定时回收,当非核心线程执行完闲置 10ms 后则回收,任务队列为延时阻塞队列。 应用场景:执行定时或周期性的任务。

private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;

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

相关文章

  • SpringBoot项目执行脚本 自动拉取最新代码并重启的实例内容

    SpringBoot项目执行脚本 自动拉取最新代码并重启的实例内容

    在本篇文章里小编给大家整理的是一篇关于SpringBoot项目执行脚本 自动拉取最新代码并重启的实例内容,有需要的朋友们参考下。
    2019-12-12
  • springboot druid数据库连接池连接失败后一直重连的解决方法

    springboot druid数据库连接池连接失败后一直重连的解决方法

    本文主要介绍了springboot druid数据库连接池连接失败后一直重连的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • SpringBoot快速过滤出一次请求的所有日志的示例代码

    SpringBoot快速过滤出一次请求的所有日志的示例代码

    在现网出现故障时,我们经常需要获取一次请求流程里的所有日志进行定位,本文给大家介绍了SpringBoot如何快速过滤出一次请求的所有日志,文中有相关的代码和示例供大家参考,需要的朋友可以参考下
    2024-03-03
  • SpringBoot+MybatisPlus+Mysql+Sharding-JDBC分库分表

    SpringBoot+MybatisPlus+Mysql+Sharding-JDBC分库分表

    本文主要介绍了SpringBoot+MybatisPlus+Mysql+Sharding-JDBC分库分表,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • maven插件spring-boot-starter-tomcat的使用方式

    maven插件spring-boot-starter-tomcat的使用方式

    这篇文章主要介绍了maven插件spring-boot-starter-tomcat的使用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • java在cmd中乱码的问题解决

    java在cmd中乱码的问题解决

    本文深入探讨了在使用Java命令行cmd时可能出现的中文乱码问题,并提供了两种解决方案,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2024-03-03
  • Java面试Socket编程常用参数设置源码问题分析

    Java面试Socket编程常用参数设置源码问题分析

    这篇文章主要为大家介绍了Java编程中关于Socket结构分析,常用参数设置源码示例以及面试中的问题分析,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2022-03-03
  • java实现文件夹解压和压缩

    java实现文件夹解压和压缩

    这篇文章主要为大家详细介绍了java实现文件夹解压和压缩,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-03-03
  • Java数据结构之HashMap和HashSet

    Java数据结构之HashMap和HashSet

    这篇文章主要介绍了HashMap和HashSet,什么是哈希表以及HashMap的部分源码解读,想了解更多的小伙伴,可以参考阅读本文
    2023-03-03
  • SpringBoot整合neo4j使用详解

    SpringBoot整合neo4j使用详解

    这篇文章将和大家详细聊聊如何在springboot应用中集成和使用neo4j,文中有详细的实现流程和实例代码,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-10-10

最新评论