java线程池核心类ThreadPoolExecutor概述
haoteby 2025-09-23 19:36 20 浏览
前言
前文java中的阻塞队列和非阻塞队列我们介绍了常用的几种队列,队列的使用很广泛,特别是一些需要生产消费模式的场景以及需要对全局的集合进行操作的场景。今天我们来讲讲其中的一种应用——线程池。
我们从java 多线程实现方式知道,有三种常见的创建线程的方法:继承Thread类、实现Runnable接口和实现Callable接口。这些线程在运行结束后都会被虚拟机销毁,如果线程数量多的话,频繁的创建和销毁线程会大大浪费时间和效率。更重要的是浪费内存,当线程执行完毕后死亡,线程对象就变成垃圾,造成GC的频繁收集和停顿。
我们使用线程池来解决这个问题,让线程运行完不立即销毁,并且重复使用,继续执行其他的任务。使用线程池来管理线程,一方面使线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。
核心类
在java.util.concurrent包中我们能找到线程池的定义,其中ThreadPoolExecutor是我们线程池的核心类,我们先看下构造函数:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
构造函数的参数含义:
- corePoolSize:指定了线程池中的线程数量,它的数量决定了添加的任务是开辟新的线程去执行,还是放到workQueue任务队列中去;
- maximumPoolSize:指定了线程池中的最大线程数量,这个参数会根据你使用的workQueue任务队列的类型,决定线程池会开辟的最大线程数量;
- keepAliveTime:当线程池中空闲线程数量超过corePoolSize时,多余的线程会在多长时间内被销毁;
- unit:keepAliveTime的单位;
- workQueue:存放提交的任务,实现队列的方式有:BlockingQueue、LinkedBlockingQueue、SynchronousQueue、SynchronousQueue等,关于队列的选择要根据实际情况来确定;
- threadFactory:线程工厂,用于创建线程,一般用默认即可;
- handler:拒绝策略;创建线程时,为了防止资源被耗尽,任务队列都会选择创建有界任务队列,但这种模式下如果出现队列已满且线程池创建的线程数达到最大的线程数时,就需要用拒绝策略来处理线程池“超载”的情况。jdk默认的处理方式是AbortPolicy,抛出异常阻止程序(除非是安全性要求极高,否则在大并发情况下使用这种做法不是很明智);DiscardPolicy,丢弃无法处理的任务;DiscardOledesPolicy,也是丢弃任务,只不过丢弃的是队列最先被添加进去,马上要执行的任务;CallerRunsPolicy,由调用者所在线程来运行任务。除了使用jdk提供的这四种策略之外,我们还可以通过实现RejectExecutionHandler来自定义拒绝策略。
一般流程图:
- 当线程池中线程数小于corePoolSize时,新提交的任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程;
- 当线程池中线程数达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行 ;
- 当workQueue已满,且maximumPoolSize > corePoolSize时,新提交任务会创建新线程执行任务;
- 当workQueue已满,且提交任务数超过maximumPoolSize,任务由RejectedExecutionHandler处理;
- 当线程池中线程数超过corePoolSize,且超过这部分的空闲时间达到keepAliveTime时,回收这些线程;
- 当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize范围内的线程空闲时间达到keepAliveTime也将回收。
提交线程池
ExecutorService pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()); pool.submit(xxRunnble); //方式1 pool.execute(xxRunnble); //方式2
两种方式的区别:execute没有返回值,如果不需要知道线程的结果就使用execute方法,性能比较好;submit返回一个Future对象如果想知道线程结果就使用submit提交,而且它能在主线程中通过Future的get方法捕获线程中的异常。
关闭线程池
pool.shutdown();//方式1 pool.shutdownNow();//方式2
两种方式的区别:shutdown不再接受新的任务,之前提交的任务等执行结束再关闭线程池;shutdownNow不再接受新的任务,试图停止池中的任务再关闭线程池,返回所有未处理的线程List列表。
总结
线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重复使用线程,线程创建的开销就被分摊到多个任务上,而且由于在请求到达时线程已经存在,所以消除线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。另外,通过适当的调整线程中的线程数目可以防止出现资源不足。
相关推荐
- 如何为MySQL服务器和客户机启用SSL?
-
用户想要与MySQL服务器建立一条安全连接时,常常依赖VPN隧道或SSH隧道。不过,获得MySQL连接的另一个办法是,启用MySQL服务器上的SSL封装器(SSLwrapper)。这每一种方法各有其...
- k8s 证书问题排查_k8s dashboard 证书
-
从去年开始一些老项目上陆陆续续出现一些列的证书问题,(证书原理这里就不说了,官方文档一堆)多数刚开始的表现就是节点的kubelet服务起不来,节点状态NotReady表现日志如下failed...
- 企业级网络互通方案:云端OpenVPN+爱快路由器+Win11互联实战
-
企业级网络互通方案:OpenVPN搭建公有云+爱快路由器+Win11三地互联实战指南「安全高效」三地局域网秒变局域网实施环境说明...
- OpenV** Server/Client配置文件详解
-
Server配置详解...
- 接口基础认知:关键信息与合规前提
-
1.核心技术参数(必记)...
- S交换机通过SSH登录设备配置示例(RADIUS认证+本地认证独立)
-
说明:●本示例只介绍设备的认证相关配置,请同时确保已在RADIUS服务器上做了相关配置,如设备地址、共享密钥、创建用户等配置。●通过不同的管理域来实现RADIUS认证与本地认证两种方式同时使用,两...
- SSL证书如何去除私钥密码保护_ssl证书怎么取消
-
有时候我们在生成证书的时候可以加入了密码保护。然后申请到证书安装到了web服务器。但是这样可能会带来麻烦。每次重启apache或者nginx的时候,都需要输入密码。那么SSL证书如何去除私钥密码保护。...
- SSL证书基础知识与自签名证书生成指南
-
一、证书文件类型解析...
- S交换机通过SSH登录设备配置示例(RADIUS认证)
-
说明:本示例只介绍设备的认证相关配置,请同时确保已在RADIUS服务器上做了相关配置,如设备地址、共享密钥、创建用户等配置。假设已在RADIUS服务器上创建了用户名yc123,密码test#123。对...
- HTTPS是什么?加密原理和证书。SSL/TLS握手过程
-
秘钥的产生过程非对称加密...
- HTTPS TLS握手流程_进行tls握手
-
1.客户端向服务器发送`ClientHello`消息,包括支持的TLS版本、加密套件、随机数等信息。2.服务器收到`ClientHello`消息后,解析其中的信息,并根据配置选择一个加密套件。3....
- Spring Boot 单点登录(SSO)实现_spring boot 单点登录jwt
-
SpringBoot单点登录(SSO)实现全指南单点登录(SingleSign-On,SSO)是一种身份验证机制,允许用户使用一组凭证登录多个相关但独立的系统。在微服务架构和企业级系统中,SS...
- 源码分享:在pdf上加盖电子签章_pdf如何加盖电子公章
-
在pdf上加盖电子签章,并不是只是加个印章图片,。而是要使用一对密钥中的私钥对文件进行签字。为啥要用私钥呢?很简单,因为公钥是公开的,其他人才可以用公钥为你证明,这个文件是你签的。这就是我们常说的:私...
- 微信支付商户API证书到期 怎么更换
-
微信支付商户API证书到期更换是一个非常重要的操作,需要仔细按照流程进行。如果证书过期,所有通过API的支付、退款等操作都会失败,将直接影响您的业务。请按照以下详细步骤进行操作:重要前提:分清...