java线程池
线程池的好处
- 降低资源消耗: 重复利用已创建的线程降低线程创建和销毁造成的消耗;
- 提高响应速度: 不需要等到线程创建就能立即执行;
- 线程的可控性: 使用线程池可以进行统一分配、调优和监控;
线程池原理

线程数量未达到 corePoolSize,则新建一个线程(核心线程)执行任务
线程数量达到了 corePools,则将任务移入队列等待
队列已满,新建线程(非核心线程)执行任务
队列已满,总线程数又达到了 maximumPoolSize,就会由拒绝策略抛出异常
线程池流程

- 线程数量小于核心线程数量则会进行核心线程的创建,不管其他线程当前是否处于空闲
- 线程数量大于等于核心线程数量则会把任务放入任务队列里面(先进先出),核心线程会循环去take队列里面的任务,获取不到任务则会进入阻塞状态,如果也对核心线程设置了超时的状态,则会在阻塞超时后进行销毁;
- 线程数量大于核心数量且任务队列已满,则会创建非核心线程,非核心线程执行完任务后会循环去take队列里面的任务,获取不到任务会进行阻塞状态,阻塞超时后进行销毁;
- 线程数量等于最大线程数量且任务队列已满,则会进行拒绝策略;
线程池使用
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
- corePoolSize:线程池核心线程数(平时保留的线程数)
- maximumPoolSize:线程池最大线程数(当workQueue都放不下时,启动新线程,最大线程数)
- keepAliveTime:超出corePoolSize数量的线程的保留时间。
- unit:keepAliveTime单位
- workQueue:任务队列,存放来不及执行的线程
- threadFactory:线程工厂
- handler:拒绝策略
任务队列
ArrayBlockingQueue:构造函数一定要传大小
LinkedBlockingQueue:构造函数不传大小会默认为(Integer.MAX_VALUE ),当大量请求任务时,容易造成 内存耗尽。
SynchronousQueue:同步队列,一个没有存储空间的阻塞队列 ,将任务同步交付给工作线程。
PriorityBlockingQueue : 优先队列
拒绝策略
AbortPolicy(默认):直接抛弃
CallerRunsPolicy:用调用者的线程执行任务
DiscardOldestPolicy:抛弃队列中最久的任务
DiscardPolicy:抛弃当前任务

线程池状态
- 运行状态:线程池创建好后就是该状态;
- 关闭状态:调用shutdown就会变成该状态,此时线程池不再接收新的任务,但会把已存在的任务处理完;
- 停止状态:调用shutdownNow变成该状态,线程池不再接收新的任务,同时会把存在的任务抛弃;
- 整理状态:调用shutdown /shutdownnow后,活动线程都降为0后会到该状态,之后会调用销毁的方法;
- 销毁状态:调用销毁方法后会到该状态;
其他问题
线程池数量如何选择?
首先要搞清楚任务的性质,是CPU密集型任务还是IO密集型任务,如果是CPU密集型任务可以配置cpu数量+1的线程,如果是IO密集型任务可以配置cpu数量*2
任务队列如何选择?
建议使用有界队列,有界队列增加系统的稳定性,采用无界队列会发生OMM的风险,
线程池监控的命令?
- takeCount:
线程池需要执行的任务数量
completedTaskCount:线程池在运行过程中已完成的任务数量,小于或等于taskCount
largestPoolSize:线程池里曾经创建过的最大线程数量。通过这个数据可以知道线程池是否曾经满过。如该数值等于线程池的最大大小,则表示线程池曾经满过
getPoolSize:线程池的线程数量。如果线程池不销毁的话,线程池里的线程不会自动销毁,所以这个大小只增不减
getActiveCount:获取活动的线程数
正文到此结束