1. 线程池的作用
- 降低资源消耗:通过重用已经创建的线程来降低线程创建和销毁的消耗
- 提高响应速度:任务到达时不需要等待线程创建就可以立即执行
- 提高线程的可管理性:线程池可以统一管理、分配、调优和监控
2. 线程池的组成
- 线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
- 2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
- 3、任务(Task):完成某个事件,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
- 4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
3. 线程池的使用逻辑
4. 常用线程池的种类
Java通过Executors提供了四种线程池,这四种线程池都是
直接或间接
配置ThreadPoolExecutor的参数实现的。newCachedThreadPool
:用来创建一个可以无限扩大的线程池,适用于负载较轻的场景,执行短期异步任务。(可以使得任务快速得到执行,因为任务时间执行短,可以很快结束,也不会造成cpu过度切换)
SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue。
- 该线程池的工作机制是:
- 没有核心线程,直接向SynchronousQueue中提交任务
- 如果有空闲线程,就去取出任务执行;如果没有空闲线程,就新建一个
- 执行完任务的线程有60秒生存时间,如果在这个时间内可以接到新任务,就可以继续活下去,否则就拜拜
newFixedThreadPool
:创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变化,适用于负载较重的场景,对当前线程数量进行限制。(保证线程数可控,不会造成线程过多,导致系统负载更为严重)newSingleThreadExecutor
:创建一个单线程的线程池,适用于需要保证顺序执行各个任务。newScheduledThreadPool
:适用于执行延时或者周期性任务。
4.1 ScheduledThreadPoolExecutor 添加任务提供了另外两个方法:
scheduleAtFixedRate() :按某种速率周期执行
scheduleWithFixedDelay():在某个延迟后执行该线程池的工作机制是:
- 调用上面两个方法添加一个任务
- 线程池中的线程从 DelayQueue 中取任务(time 大于等于当前时间的)
- 然后执行任务
- 执行完的任务修改time到指定时间,重新加入队列
- 5. 线程池的参数
corePoolSize
:线程池中的核心线程数- 核心线程会一直存活,即使是闲置状态
- CPU密集型的任务(加密、解密、压缩、复杂计算),一般core设置为CPU核数 + 1, 防止频繁的上下文切换;
- IO密集型的任务(读写数据库、网络请求、文件读写),一般core设置为CPU核数 * 2
- 具体要设置多少,还是测试、生产环境需要反复调试、修改
maximumPoolSize
:线程池中最大线程数- 一般生产环境和core配的一致,防止线程池震荡
keepAliveTime:闲置超时时间
- poolSize > corePoolSize 后创建的为闲置线程 - 如果服务波峰之后有较长时间的波谷,可以考虑尽快超时回收; 如果是密集的波峰,就要配久一点再超时
- unit:keepAliveTime 超时时间的单位(时/分/秒等)
- workQueue:线程池中的任务队列
- threadFactory:为线程池提供创建新线程的线程工厂
rejectedExecutionHandler
:线程池任务队列超过最大值之后的拒绝策略java默认有4种实现, 如果不指定,默认选择Abort, 下面排列由最消极到最积极 - DiscardPolicy, 丢弃任务,但是不抛出异常
DiscardOldestPolicy 丢弃队列最前面的任务,然后提交当前Task到队列尾部
- AbortPolicy, 丢弃任务并抛出RejectedExecutionException
- CallerRunsPolicy 由调用线程处理该任务
- 6. 为什么要使用阻塞队列
- 防止线程无限制的创建、浪费内存导致OOM or 浪费CPU频繁进行上下文切换
- 阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程,使得线程进入wait状态,释放cpu资源。
- 当队列中有任务时才唤醒对应线程从队列中取出消息进行执行。
参考:《2020最新Java基础精讲视频教程和学习路线!》
链接:https://juejin.cn/post/693865...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。