线程池详解

在了解线程池之前,要先理解一个问题

为什么要使用线程池

a.线程池可以更加有效的利用cpu资源,减少创建线程,销毁线程带来的多余的开销

b.线程池能控制线程的并发数目,管理线程并发问题

c.线程池用一些其他的特性,延时调度执行,例如:scheduleThreadPool能使线程定时调度执行

 

我们先看下线程池的构造方法:

int corePoolSize => 该线程池中核心线程数

       核心线程指的是在线程池中不会被回收的线程,当然也可以通过设置allowCoreThreadTimeOut 为true将超过keepAliveTime空闲的核心线程销毁。

int maximumPoolSize => 最大线程数

       最大线程是指核心线程和非核心线程的最大容量,即线程池的最大值

long keepAliveTime => 闲置存活时间

       一般是指非核心线程的空闲存活时间,但是allowCoreThreadTimeOut 为true时也适用于核心线程

TimeUnit unit =>闲置存活时间的单位(枚举类型)

       NANOSECONDS : 1微毫秒 = 1微秒 / 1000,MICROSECONDS : 1微秒 = 1毫秒 / 1000,MILLISECONDS : 1毫秒 = 1秒 /1000,SECONDS : 秒,MINUTES : 分,HOURS : 小时,DAYS : 天

BlockingQueue<Runnable> workQueue =>线程池的任务队列

       1.1 直接提交的任务队列(SynchronousQueue)

       (1)      SynchronousQueue没有容量。

       (2)      提交的任务不会被真实的保存在队列中,而总是将新任务提交给线程执行。如果没有空闲的线程,则尝试创建新的线程。如果线程数大于最大值maximumPoolSize,则执行拒绝策略。

       1.2 有界的任务队列(ArrayBlockingQueue)

       (1)      创建队列时,指定队列的最大容量。

       (2)      若有新的任务要执行,如果线程池中的线程数小于corePoolSize,则会优先创建新的线程。若大于corePoolSize,则会将新任务加入到等待队列中。

       (3)      若等待队列已满,无法加入。如果总线程数不大于线程数最大值maximumPoolSize,则创建新的线程执行任务。若大于maximumPoolSize,则执行拒绝策略。

       1.3 无界的任务队列(LinkedBlockingQueue)

       (1)      与有界队列相比,除非系统资源耗尽,否则不存在任务入队失败的情况。

       (2)      若有新的任务要执行,如果线程池中的线程数小于corePoolSize,线程池会创建新的线程。若大于corePoolSize,此时又没有空闲的线程资源,则任务直接进入等待队列。

       (3)      当线程池中的线程数达到corePoolSize后,线程池不会创建新的线程。

       (4)      若任务创建和处理的速度差异很大,无界队列将保持快速增长,直到耗尽系统内存。

       (5)     使用无界队列将导致在所有 corePoolSize 线程都忙时,新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize(因此,maximumPoolSize 的值也就无效了)。当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。

       1.4 优先任务队列(PriorityBlockingQueue)

       (1)      带有执行优先级的队列。是一个特殊的无界队列。

       (2)      ArrayBlockingQueue和LinkedBlockingQueue都是按照先进先出算法来处理任务。而PriorityBlockingQueue可根据任务自身的优先级顺序先后执行(总是确保高优先级的任务先执行)。

       1.5 延迟队列(DelayQueue)

       队列内元素必须实现Delayed接口,这就意味着你传进去的任务必须先实现Delayed接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务

ThreadFactory =>线程工厂用来产生线程

       就是一个接口,newThread方法就是用来生产线程的,子类需要实现这个方法来根据自己规则生产相应的线程。

RejectedExecutionHandler handler =>拒绝策略

   当线程池线程大于最大线程容量时,执行拒绝策略,目前

  • AbortPolicy
  • 丢掉这个任务并且抛出RejectedExecutionException异常
  • DiscardPolicy
  • 会直接丢掉这个任务并且不会有任何异常
  • DiscardOldestPolicy
  • 会将最早进入队列的任务删掉腾出空间,再尝试加入队列
  • CallerRunsPolicy
  • 如果添加到线程池失败,那么主线程会自己去执行该任务,不会等待线程池中的线程去执行
  • 自定义
  • 自己定义一个拒绝策略,只要实现RejectedExecutionHandler接口,并且实现rejectedExecution方法就可以了

 

ThreadPoolExecutor的策略

       线程数量未达到corePoolSize,则新建一个线程(核心线程)执行任务

       线程数量达到了corePools,则将任务移入队列等待

       队列已满,新建线程(非核心线程)执行任务

       队列已满,总线程数又达到了maximumPoolSize,就会由上面那位星期天(RejectedExecutionHandler)抛出异常

 

常见四种线程池

CachedThreadPool()

       使用 直接提交的任务队列(SynchronousQueue)

可缓存线程池:

  1. 线程数无限制
  2. 有空闲线程则复用空闲线程,若无空闲线程则新建线程
  3. 一定程序减少频繁创建/销毁线程,减少系统开销

创建方法:

       ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

源码:

FixedThreadPool()

       使用 无界的任务队列(LinkedBlockingQueue)

定长线程池:

  1. 可控制线程最大并发数(同时执行的线程数)
  2. 超出的线程会在队列中等待

创建方法:

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads);

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads, ThreadFactory threadFactory);

源码:

ScheduledThreadPool()

使用 延迟队列(DelayQueue)

定长线程池:

  1. 支持定时及周期性任务执行。

创建方法:

 ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);

源码:

SingleThreadExecutor()

使用 无界的任务队列(LinkedBlockingQueue)

单线程化的线程池:

  1. 有且仅有一个工作线程执行任务
  2. 所有任务按照指定顺序执行,即遵循队列的入队出队规则

创建方法:

ExecutorService singleThreadPool = Executors.newSingleThreadPool();

源码:

 

线程池常问的一些问题:

ExecutorService .execute和ExecutorService.submit方法有什么区别 executer提交任务但是不会返回结果,不会返回异常,submit 会返回结果和异常

### Java 线程池详解 #### 创建线程池的方式 Java 提供了几种创建线程池的方法,最常用的是通过 `Executors` 工厂类来获取预配置好的线程池实例。然而,在实际项目中更推荐使用 `ThreadPoolExecutor` 构造器来自定义参数,以获得更好的灵活性和性能控制[^1]。 ```java // 不推荐的做法:固定大小的缓存线程池可能导致资源浪费或耗尽 ExecutorService cachedPool = Executors.newCachedThreadPool(); // 推荐做法:自定义 ThreadPoolExecutor 参数设置 ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build(); ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, namedThreadFactory); ``` #### 关键组件说明 - **核心线程数 (`corePoolSize`)** 定义了即使处于空闲状态也会被保留在线程池中的最小线程数量。 - **最大线程数 (`maximumPoolSize`)** 设置允许的最大活动线程数目;当现有任务队列已满而又有新的提交任务时才会触发扩容至该上限。 - **存活时间 (`keepAliveTime`)** 非核心线程闲置后的自动回收等待周期长度。 - **阻塞队列 (`workQueue`)** 存储待处理的任务对象集合,不同类型的队列会影响吞吐量表现及拒绝策略行为。 - **线程工厂 (`threadFactory`)** 负责生产新线程实体,默认实现较为简单,通常建议开发者根据应用场景定制化命名规则以便于调试跟踪。 #### 常见错误与优化技巧 忽视对线程池内部运行状况监控是常见的失误之一。应当定期审查并调整相关参数,确保其适应当前负载需求变化趋势。另外需要注意捕获未预见异常情形下的恢复机制设计,防止因个别失败案例影响整体服务稳定性[^2]。 #### 实践指南 对于Web容器如Tomcat而言,内置有经过优化过的专用线程管理模块用于支撑高并发请求场景下高效运作的要求。尽管如此,了解基础概念仍然有助于更好地理解框架底层运作机理,并能在必要时候做出针对性调优措施。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值