## Java线程池概念
顾名思义,管理线程的池子,相比于手工创建、运行线程,使用线程池,有如下优点
* 降低线程创建和销毁线程造成的开销
* 提高响应速度。任务到达时,相对于手工创建一个线程,直接从线程池中拿线程,速度肯定快很多
* 提高线程可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统稳定性,使用线程池可以进行统一分配、调优和监控
## Java线程池创建
无论是创建何种类型线程池(`FixedThreadPool`、`CachedThreadPool`...),均会调用`ThreadPoolExecutor`构造函数,下面详细解读各个参数的作用
```
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
```
* **corePoolSize**:核心线程最大数量,通俗点来讲就是,线程池中**常驻线程**的最大数量
* **maximumPoolSize**:线程池中运行最大线程数(包括核心线程和非核心线程)
* **keepAliveTime**:线程池中空闲线程(仅适用于非核心线程)所能存活的最长时间
* **unit**:存活时间单位,与keepAliveTime搭配使用
* **workQueue**:存放任务的阻塞队列
* **handler**:线程池饱和策略
## 线程池执行流程
当提交一个新任务,线程池的处理流程如下:
* 判断线程池中核心线程数是否已达阈值`corePoolSize`,若否,则创建一个新核心线程执行任务
* 若核心线程数已达阈值`corePoolSize`,判断阻塞队列`workQueue`是否已满,若未满,则将新任务添加进阻塞队列
* 若满,再判断,线程池中线程数是否达到阈值`maximumPoolSize`,若否,则新建一个非核心线程执行任务。若达到阈值,则执行**线程池饱和策略**。
线程池饱和策略分为一下几种:
1. AbortPolicy:直接抛出一个异常,**默认策略**
2. DiscardPolicy: 直接丢弃任务
3. DiscardOldestPolicy:抛弃下一个将要被执行的任务(**最旧任务**)
4. CallerRunsPolicy:主线程中执行任务
从流程角度,更形象的图:
![](https://img.kancloud.cn/a7/61/a761e40f1306f34e6f4ab3a08eee00dc_720x290.png)
从结构角度,更形象的图:
![](https://img.kancloud.cn/ad/fa/adfad43f3d27ff60a67170966bf4bb9b_904x595.png)
## 几种典型的工作队列
* **ArrayBlockingQueue**:使用数组实现的有界阻塞队列,特性**先进先出**
* **LinkedBlockingQueue**:使用链表实现的阻塞队列,特性先进先出,可以设置其容量,默认为`Interger.MAX_VALUE`,特性**先进先出**
* **PriorityBlockingQueue**:使用平衡二叉树**堆**,实现的具有**优先级**的无界阻塞队列
* **DelayQueue**:无界阻塞延迟队列,队列中每个元素均有过期时间,当从队列获取元素时,只有过期元素才会出队列。队列头元素是最块要过期的元素。
* **SynchronousQueue**:**一个不存储元素的阻塞队列**,每个插入操作,必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态
## 几种典型的线程池
1. SingleThreadExecutor
```
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
```
创建单个线程。它适用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程是活动的应用场景。
`SingleThreadExecutor`的`corePoolSize`和`maximumPoolSize`被设置为1,使用无界队列`LinkedBlockingQueue`作为线程池的工作队列。
![](https://img.kancloud.cn/80/f0/80f0194c7618c4c62e9358bc82297246_674x342.png)
* 当线程池中没有线程时,会创建一个新线程来执行任务。
* 当前线程池中有一个线程后,将新任务加入`LinkedBlockingQueue`
* 线程执行完第一个任务后,会在一个无限循环中反复从`LinkedBlockingQueue`获取任务来执行。
**使用场景**:适用于串行执行任务场景
2. FixedThreadPool
```
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
```
`corePoolSize`等于`maximumPoolSize`,所以**线程池中只有核心线程**,使用无界阻塞队列`LinkedBlockingQueue`作为工作队列
`FixedThreadPool`是一种线程数量固定的线程池,当线程处于空闲状态时,他们并不会被回收,除非线程池被关闭。当所有的线程都处于活动状态时,新的任务都会处于等待状态,直到有线程空闲出来。
![](https://img.kancloud.cn/63/85/638574c40ab73c6a1fa2e397c9f45435_674x463.png)
* 如果当前运行的线程数少于`corePoolSize`,则创建新线程来执行任务。
* 在线程数目达到`corePoolSize`后,将新任务放到`LinkedBlockingQueue`阻塞队列中。
* 线程执行完(1)中任务后,会在循环中反复从`LinkedBlockingQueue`获取任务来执行。
**使用场景**:适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务。
3. CachedThreadPool
```
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
```
核心线程数为0,总线程数量阈值为`Integer.MAX_VALUE`,即**可以创建无限的非核心线程**
**执行流程**
* 先执行`SynchronousQueue`的`offer`方法提交任务,并查询线程池中是否有空闲线程来执行`SynchronousQueue`的`poll`方法来移除任务。如果有,则配对成功,将任务交给这个空闲线程
* 否则,配对失败,创建新的线程去处理任务
* 当线程池中的线程空闲时,会执行`SynchronousQueue`的`poll`方法等待执行`SynchronousQueue`中新提交的任务。若等待超过60s,空闲线程就会终止
流程形象图
![](https://img.kancloud.cn/e9/5f/e95f68ff0bfda10fcaf5ea157265a355_832x839.png)
### 结构形象图
![](https://img.kancloud.cn/66/41/664185d6cea29311bde346a2dc15ac5f_674x519.png)
**使用场景**:**执行大量短生命周期任务**。因为`maximumPoolSize`是无界的,所以提交任务的速度 > 线程池中线程处理任务的速度就要不断创建新线程;每次提交任务,都会立即有线程去处理,因此`CachedThreadPool`适用于处理大量、耗时少的任务。
4. ScheduledThreadPoolExecutor
```
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
```
线程总数阈值为`Integer.MAX_VALUE`,工作队列使用`DelayedWorkQueue`,非核心线程存活时间为0,所以**线程池仅仅包含固定数目的核心线程。**
两种方式提交任务:
* scheduleAtFixedRate: 按照固定速率周期执行
* scheduleWithFixedDelay:上个任务延迟固定时间后执行
**使用场景**:周期性执行任务,并且需要限制线程数量的场景
- 开发语言
- java
- Java基础篇
- Java多线程篇
- 进程和线程的区别,进程间如何通信
- 什么是线程上下文切换
- 什么是死锁
- 死锁的必要条件
- Synchrpnized和lock的区别
- 什么是AQS锁
- 为什么AQS使用的双向链表
- 有哪些常见的AQS锁
- sleep()和wait()的区别
- yield()和join()区别
- Java线程池
- SpringBoot
- spring boot 项目开发常用目录结构
- Mybatis-Plus
- MyBatisPlus的CRUD操作
- Mybatis-Plus主键ID生成策略
- JVM
- JVM组成
- 字节码文件的组成
- 类的生命周期
- JVM、JRE和JDK
- arthas
- 使用阿里arthas不停机解决线上问题
- Java IO
- php
- 安装swoole
- composer部分
- windows安装composer
- composer PSR-4映射
- swoole部分
- swoole安装
- thrift部分
- linux下安装thrift
- PHP使用Thrift
- lnmp部分
- 架构的工作原理
- tp5框架生命周期
- zookeeper部分
- zookeeper安装
- sort
- TCP和UDP的区别
- 软件
- xdebug
- vscode+phpstudy+xdebug无法断点(踩坑记)
- Hyperf框架
- 注解
- 开发方案
- 抖音
- 抖音达人视频发布与统计
- 安全问题
- 微信
- 微信公众平台怎样实现用户点击链接向公众号发消息
- CDN加速OSS计费说明
- 程序设计
- 正则表达式
- 面向对象
- 设计模式
- 创建型模式
- 工厂模式
- 单例模式
- 结构型模式
- 适配器模式
- 行为型模式
- 策略模式
- 观察者模式
- 算法部分
- 位运算
- 排序算法
- 双指针
- 贪心算法
- 动态规划
- 二分查找
- 华为题库
- 技术栈
- mq
- MQ 的优势和劣势
- rabbitmq部分
- windows安装rabbitmq
- RabbitMQ 简介
- 工作模式
- 高级特性-消息可靠投递-confirm
- 高级特性-消息可靠投递-return
- 高级特性-Consumer Ack
- 高级特性-消费端限流
- 高级特性-TTL
- 高级特性-死信队列
- Centos7下安装rabbitmq
- 数据库
- MongoDB
- MongoDB 相关概念
- Mysql
- 索引总结
- MySQL架构图
- InnoDB和MyISAM的区别
- 索引设计与优化
- 悲观锁和乐观锁
- mysql如何解除死锁状态
- 查询慢
- 数据库主键的优缺点
- MySQL锁详解
- SQL语句分类
- 开查询账号
- 数据库迁移
- MySQL实战知识点
- mysql清理binlog日志
- 面试总结
- 事务隔离
- 聚集索引与非聚集索引
- B树和B+树
- docker
- docker-desktop安装的坑点
- docker在linux平台下安装
- Ubuntu安装Docker
- 常用命令
- 适用于 Linux 的 Windows 子系统没有已安装的分发版
- docker核心架构图
- docker安装lnmp环境
- docker安装redis
- dockerfile
- docker-compose
- linux
- Ubuntu 更换国内源
- centos
- 常用命令
- virtualbox
- 关于VirtualBox安装Ubuntu时界面显示不全,没有下一步选项
- linux复制当前目录到其子目录下
- 命令
- cat和>、>>
- crontab命令
- 查看当前目录的文件大小
- shell登录和非shell登录
- nginx
- 正向代理
- 反向代理
- 负载均衡
- 分割Nginx的access.log日志并保留30天一个月时长,自动删除多余的日志
- linux安装nginx
- git
- 生成秘钥
- 常用命令
- Linux中git保存用户名密码
- git清除账号密码
- 设置git store 存储账号密码
- git submodule 使用小结
- 微服务
- 微服务技术栈
- nacos
- Nacos服务分级存储模型
- Nacos配置管理-配置热更新
- Nacos集群搭建
- 微服务保护
- 初识Sentinel
- 隔离和降级
- es
- DSL查询语法-相关性算法
- DSL查询语法-FunctionScoreQuery
- DSL查询语法-BooleanQuery
- 搜索结果处理-排序
- es深度分页问题
- 自动补全
- elasticsearch 设置密码
- redis
- redis简介
- 安装redis扩展
- redis数据类型
- redis常见问题
- PHP 使用 Redis 实现分布式锁
- 缓存更新策略
- [ Redis ] AOF 和 RDB 的相关介绍以及相关配置
- 分布式锁的8大坑
- 分布式锁-Redisson
- 内存回收
- UV统计
- Redis主从集群
- redis哨兵
- Redis安装目录下常见文件
- 通讯原理概述
- linux安装redis
- windows
- Win系统端口被占用
- Windows10 WSL2限制cpu和内存
- jekins
- 持续集成
- centos卸载gitlab
- jenkins搭配gitlab的webhook实现自动化部署
- 大数据
- Linux集群分发脚本xsync
- hadoop
- hadoop安装
- hadoop配置文件
- clickhouse
- ClickHouse 安装部署
- flink
- 数据仓库
- zookeeper
- zookeeper分布式安装
- ZK集群启动停止脚本
- kafka
- kafka分布式安装
- kafka集群启动停止脚本
- flume
- flume分布式安装
- Flume配置
- Flume使用
- maxwell
- Maxwell简介
- Maxwell部署
- Maxwell使用
- MaxwellBootstrapUtility - Connections could not be acquired from the underlying database
- 线上事故