关于线程池的创建方式,可以是通过Executors
创建,也可以是通过直接new ThreadPoolExecutor(...)
来创建。但是阿里巴巴规约中要求使用第2种方式。
线程池的运行规则
如上图所示,线程池包含的信息有:核心线程、阻塞队列、临时线程、拒绝策略。
上图的线程池用代码来表达的话就是:
new ThreadPoolExecutor(3,// 核心线程
5,// 总线程
1,// 可空闲时间
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5), //阻塞队列
Executors.defaultThreadFactory(), //线程工厂
new ThreadPoolExecutor.AbortPolicy()); //拒绝策略
流程描述:
- 任务进入线程池,线程池创建线程
- 当3个核心线程创建并正在使用时,再次进来的线程被丢入阻塞队列
- 如果阻塞队列被塞满后,仍然有线程进入,则创建临时线程,但是在不超过最大线程数5的情况下
- 如果无法创建临时线程,则线程池使用设置的拒绝策略执行处理
线程执行完任务后,空闲keepAliveTime时间后,且池内线程数大于核心线程数时,自动销毁。
线程池的拒绝策略
我们可以看到线程池的最后一个参数是用来指定拒绝策略的。那么具体有哪几种拒绝策略呢?
AbortPolicy
CallerRunsPolicy
DiscardPolicy
DiscardOldestPolicy
丢掉最早进入队列中的任务。注意是最早进入队列中的任务
自定义线程工厂
线程池创建线程是通过指定的线程工厂创建的。其创建的线程名称是自动生成的。但是在阿里规约中,不推荐这么做。
太棒了,同时给出了如何自定义线程工厂的例子。
public class MyThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger nextId = new AtomicInteger(1);
public MyThreadFactory(String namePrefix) {
this.namePrefix = namePrefix;
}
@Override
public Thread newThread(Runnable r) {
String nowThreadName = namePrefix + "-" + nextId.getAndIncrement();
Thread thread = new Thread(null, r, nowThreadName);
return thread;
}
}