线程池
线程池的作用
方便管理线程、提升效率
使线程间相互配合、满足业务逻辑
为什么用线程池?
- 线程的生命周期开销是很高的,特别是创建和销毁
- 过多线程会占用太多内存
使用线程池的好处
- 加快响应速度
- 合理使用CPU和内存
- 统一管理资源
使用场合
-
服务器接收处理大量请求时(Tomcat)
-
日常开发中遇到需要创建5个线程的情况,使用线程池来管理
手动创建线程
添加规则
-
线程数少于CorePoolSize,即使其他线程处于空间状态,也会创建新的线程来运行任务
-
当线程数等于或大于CorePoolSize,但少于MaxiumPoolSzie,则将任务放进队列
-
队列已满,线程数小于MaxPoolSize,则创建新线程来运行任务
-
线程数>=MaxPoolSzie,队列也满了,则拒绝该任务
增减线程的特点
-
CorePoolSize=MaximumPoolSize,固定大小线程池
-
线程池希望保持较少的线程数,并只有在负载很大的时候才使用它
-
设置很大的maximumpoolSize,并只有在负载很大的时候才使用它
线程池常用队列
直接交接:SynchronousQueue 容量为0
无界队列:LinkedBlockingQueue 容易导致OOM
有界队列:ArrayBlockingQueue
自动创建线程池
- newFixedThreadPool(4)——OOM——0容量
- newSingleThreadExecutor——线程数1
- newCacheThreadPool——没队列,MaximumPoolSize很大,corePoolsize为0,容易导致OOM,But会回收线程
- newSecheduledThreadPool——延迟x时间执行任务,并以一定的频率重复运行
停止线程池的正确方法
shutdown() 停止接收新任务、处理完队列中的任务后关闭
shutdownNow()——发出中断信号,返回队列中的任务
常用方法
- isshutdown
- isterminated
- awaitTerminated——在规定时间内完成任务,此时队列会处于阻塞状态
拒绝任务时机
◆ shutdown,当Executor关闭时
◆ 当Excutor对最大线程和工作队列容量已经饱和时
拒绝任务的策略
-
AbortPolicy——抛异常
-
DiscardPolicy——不通知
-
DiscardOldestPolicy——丢弃队列最前面的任务
-
CallerRunsPolicy——让提交的任务线程执行
线程池的原理
让相同的线程去执行不同的任务
线程池的状态
-
running——接收新任务并处理排队任务
-
shutdown——不接受新任务, 处理排队任务
-
stop——不接受新任务,也不接受排队任务,中断正在进行的任务
-
tidying——所有任务终止,workcount为0时,转到这状态,并运行terminated();
-
terminated——terminated()运行完成
使用线程池注意
- 避免任务堆积
- 避免线程数过度增加
- 排查线程泄露(排查线程数量)
线程池线程数的设定,使用计算公式
CPU核数X(1+平均等待时间/平均工作时间)