千家信息网

Java并发之怎么使用线程池

发表于:2025-11-07 作者:千家信息网编辑
千家信息网最后更新 2025年11月07日,这篇文章主要介绍"Java并发之怎么使用线程池",在日常操作中,相信很多人在Java并发之怎么使用线程池问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Java并发之怎么
千家信息网最后更新 2025年11月07日Java并发之怎么使用线程池

这篇文章主要介绍"Java并发之怎么使用线程池",在日常操作中,相信很多人在Java并发之怎么使用线程池问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Java并发之怎么使用线程池"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

线程池的作用

池化技术是一种很常见的计算机技术,主要是为了复用和提高性能,如内存池、连接池、对象池等。线程池也不例外,他的主要作用如下:

  • 提高性能:线程的频繁创建和销毁会产生的很大的系统开销,线程池中的线程复用可以大幅度的减少这种不必要的开销。

  • 复用和管理:方便对池子中的线程进行管理和复用,避免在生产环境中大量的创建线程。

  • 解耦:只暴露提交任务的接口,将线程池的创建、销毁等工作与业务解耦。

JDK 在并发包中为我们定义了一套 Executor 框架,帮助开发人员有效地进行线程控制,有基础的线程池类、有线程池工厂,但是最最重要还是 ThreaPoolExecutor,也是面试中最常问的知识点。本文重点介绍 ThreaPoolExecutor 的原理。

线程池的参数说明

ThreaPoolExecutor(     int corePoolSize,     long keepAliveTime,     TimeUnit unit,     BlockingQueue workQueue,     ThreadFactory threadFactory,     RejectedExecutionHandler handler) )

ThreaPoolExecutor 参数的含义如下

  • corePoolSize: 线程池中核心线程的数量。

  • maximumPoolSize: 线程池中的最大线程数量。

  • keepAliveTime: 当线程池数量超过 corePoolSize 时,多余的空闲线程的存活时间。即超过 coolPoolSize 的空闲线程在 多长时间内,会被销毁。

  • unit: keepAliveTime 的单位,可以为 时、分、秒等多种值。

  • workQueue: 任务队列,存放被提交但尚未被执行的任务。

  • threadFactory: 线程工厂,用于创建线程,一般用默认即可。

  • handler: 拒绝策略,当线程池处理不过来任务时,如何拒绝任务。

以上参数中 workQueue、threadFactory、handler 相对复杂,需要单独介绍,下面主要介绍下 ThreadFactory 和 RejectedExecutionHandler

1. 线程工厂:ThreadFactory

线程池中的线程都由 TrheadFactory 定义的线程工厂来创建,它是一个接口只有 Thread newThread(Runnable r) 方法,用来创建线程。虽然创建 ThreadPoolExecutor 的时候可以不指定该参数,但是阿里巴巴编码规约建议最好指定该参数,有以下几个好处:

  • 跟踪线程池在何时、创建了多少线程。

  • 可以自定义线程池的名称、组以及优先级等信息。

  • 设置线程的其他状态等,如守护进程。

2. 拒绝策略:RejectedExecutionHandler

当线程池线程数量达到 maxPoolSize 大小时,再提交新的任务会执行拒绝策略,JDK 定义了四种拒绝策略:

  • AbortPolicy 该策略直接抛出异常

  • CallerRunsPolicy 调用者线程处理任务,该策略并不是真正的丢弃任务,会让当前线程来执行被抛弃的任务,由于只有一个线程,所有的任务会被串行执行。

  • DiscardOldestPolicy 丢弃最老的一个请求,即队列头部的即将被执行的任务,并尝试再次提交当前任务。

  • DiscardPolicy 该策略默默丢弃无法处理的任务。

以上四种拒绝策略都继承了接口 RejectedExecutionHandler 并实现该接口的 rejectedExecution(Runnable r, ThreadPoolExecutor executor) 方法。如果以上四种拒绝策略都满足不了你的需求,可以自定义拒绝策略,继承接口 RejectedExecutionHandler 并实现方法即可。

线程池的调度逻辑

ThreaPoolExecutor 对提交的任务处理逻辑如下图,

1. 提交任务时:

  • 如果线程池中的线程数小于 corePoolSize (无论是否有空闲线程),创建新的线程(谓之核心线程)来处理。

  • 如果线程池中的线程数已经大于或者 corePoolSize ,新提交的任务将被放置到等候队列中,等待调度。

  • 如果等待队列已满,并且线程池中的线程数量小于 maxPoolSize,将继续创建新线程处理任务。

  • 如果队列已满且线程数量也达到了上限,将使用拒绝策略来处理。

2. 任务进行中时:

当队列中的任务已经执行完,部分线程开始空闲,非核心线程会在空闲后的 keepAliveTime 的时间内自行销毁。

而空闲核心线程是否退出取决于线程池的另一个参数 allowCoreThreadTimeOut 。当配置为 true 的时候,即使是核心线程,超时也会退出。

线程池的生命周期

线程池同线程一样也有自己的生命周期,包括 RUNNING、SHUTDOWN、STOP、TIDYING 和 TERMINATED 五种状态,他们的转换关系如下图,并且这些转换时不可逆的。

1. RUNNING

该状态是线程池的工作状态,能够接受新任务以及对接受的任务进行处理。线程池的初始状态,即线程创建成功后就处理此状态。

2. SHUTDOWN

关闭状态,线程池不再接受新的任务,但是能继续处理提交到线程池中的任务。线程状态 RUNNING 的情况下调用 shutdown() 方法进入该状态。

3. STOP

停止状态,线程池不接受新的任务,也不处理阻塞队列中的任务,同时会中断正在执行任务的线程。在线程处于 RUNNING 或者 SHUTDOWN 状态下调用 shutdownNow() 方法进入该状态。

4. TIDYING

所有任务都销毁了,workCount 为 0,会自动从 RUNNING 或者 STOP 状态转化为 TIDYING 状态。在转换过程中会调用 terminated() 方法,ThreadPoolExecutor 类的 ternimated() 方法为空,如果想在线程池变成 TIDYING 的时候有所处理,可以重载该方法。

线程池在 SHUTDOWN 状态下,阻塞队列为空并且执行任务为空时转换为 TIDYING 状态;线程池在 STOP 状态下,执行的任务为空时转换为 TIDYING 状态。

5. TERMINATED

结束状态,线程池的最终状态,该状态的线程池不会再有任何操作。线程池执行 terminated() 方法后处于该状态。

JDK 四种线程池

了解 ThreaPoolExecutor 的基本原理后再来看看 JDK 在 Executors 中为开发人员定义的四个线程池工厂方法,其实它们内部调用的是 ThreaPoolExecutor,只是使用了不同的参数,下面来了解下它们的特性。

newFixedThreadPool() 方法:该方法返回一个固定线程池数量的线程,提交任务时如果线程池中有空闲线程,则立即执行,没有则新的任务会被缓存在一个任务队列中,它创建线程池的代码如下:

public static ExecutorService newFixedThreadPool(int nthread) {   return new ThreadPoolExecutor(nthread,                                  nthread,                                  0L,                                  TimeUnit.MILLSECCONDS,                                  new LikedBlockingQueue()) }

newSingleThreadExecutor() 方法:该方法返回只有一个线程的线程池,如果多余的任务提交到线程池,则被提交到任务队列中。它创建线程池代码如下:

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

newCachedThreadPool() 方法:该方法返回一个可根据实际情况调整线程数的线程池,它的核心线程数为 0 ,线程总数为 Integer.MAX_VALUE ,队列采用的是 SynchronousQueue,这样即使线程满,任务也不能提交到队列中。

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

newScheduledThreadPool():该方法一个固定长度的线程池,并且以延迟或者定时的方式去执行任务。它的队列使用 DelayedWorkQueue,所以任务必须继承 Delay 接口。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {     return new ScheduledThreadPoolExecutor(corePoolSize); }  public ScheduledThreadPoolExecutor(int corePoolSize) {     super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,           new DelayedWorkQueue()); }

到此,关于"Java并发之怎么使用线程池"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

线程 任务 状态 方法 队列 处理 策略 参数 数量 空闲 接口 工厂 核心 复用 学习 只有 时候 时间 帮助 人员 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 南京通财网络技术有限公司 大学计算机网络技术期末复习 网络网络安全协议包括 上海智能化软件开发系列 数据库中常用运算符的优先级 水利软件开发需要专家评审么 db2查看数据库用户密码 中国网络安全最新动态 未来网络安全就业 南京海葵网络技术公司 数字电影服务器解码卡号怎么查看 网络安全谁使用谁负责还是谁主责 asp.net数据库教程 银行网络安全的因素不包括 大学信息技术数据库 开展期末网络安全 网络安全工程师培训中公教育 服务器中的超级附魔台怎么用 上海访客管理软件开发价钱 未来科技和互联网 冒险岛怎样打开服务器 软件开发公司存在的问题 怎样注意网络安全英文 软件开发去什么样的公司好 企业管理器和服务器 在什么时候判断数据库连接成功 csgo服务器架设 武汉晓鹏互联网络科技有限公司 小伙自学网络技术 服务器断开请稍后再试是什么意思
0