更多Java技术文章,关注公众号,分享源码阅读笔记
1.特点
- 线程池是一个三级存储结构,线程先放入核心线程池,满了之后放到缓存队列当中,最后如果缓存队列也满了则扩容新线程。
- 实现原理
2.1 构造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
- 添加worker线程一直执行run,去workQueue获取任务并执行;blockQueue的take方法是阻塞的,若队列为空,则挂起;挂起超过一定时间,就销毁线程。
3. 接口
- Executor
- ExecutorService
4. 自定义线程池
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(核心线程数)
- maximumPoolSize(最大线程数)
- keepAliveTime(空闲生存时间)
- TimeUnit(时间单位)
- BlockingQueue(任务队列选用阻塞队列)
- ThreadFactory(线程工厂)
- RejectedExecutionHandler(拒绝策略)
线程工厂可以自定义,拒绝策略也可以,jdk默认提供以下拒绝策略
- 抛异常
- 扔掉,不理会
- 扔掉排队时间最长的
- 调用者处理服务
5. 配合工具
- Runable
- Callable,类似于Runable,但有返回值Future
- 传入一个Callable,使用方式和new一个Thread类似,FutureTasktask
= new FutureTask<>(new Callable())
6. 线程池类型
6.1 FixedThreadPool
- LinkedBlockingQueue
- 核心线程是固定的,最大线程和和核心线程参数相等
- 线程池大小,可通过期望利用率计算,线程池线程数量=处理器数量*利用率,合理利用可提高利用率可以提高吞吐量
6.2 SingleThreadPool
- LinkedBlockingQueue
- 单线程的,扔进去的任务顺序处理
6.3 CachedThreadPool
- SynchronousQueue
- 可以有很多线程,但是如果超过60秒这个线程没有被调用,则会被回收
6.4 ScheduledThreadPool
- DelayedWorkQueue
- 定时任务线程
6.5 SingleThreadScheduledExecutor
- DelayedWorkQueue
6.6 ForkJoinPool
- 任务分叉进行然后结果jion起来的线程池.
6.7 WorkStealingPool
- 多个Work Queue线程,其实每个线程都是一个ForkJoinPool
- 采用 work stealing算法,当一个线程空闲了,发现其他线程在忙,会帮其他线程消费任务
7. 线程池生命周期
8. 如何关闭线程池
8.1 shutdown
- 当调用了shutdown()方法时,便进入关闭状态,此时意味着 ExecutorService不再接受新的任务,但它还在执行已经提交了的任务,当已经提交了的任务执行完后,便到达终止状态。
8.2 shutdownNow
- 阻止等待任务启动并试图停止当前正在执行的任务,即停止当前执行的task,并返回尚未执行的task的list。
9. 如何自定义线程提高吞吐量
9.1 吞吐量公式
9.2 提高方式
- 提高C,cpu数量
- 降低Tw
- 降低Tc
- 需要合理估算CPU利用率,线程过多会造成切换频繁
9.3 实际操作
- 根据要求和场景配置,然后压测调试,达到最好的效果。