为什么要使用ThreadPoolExecutor?
线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这
样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
另外使用Executors直接去创建,允许的请求或创建的队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
参数详解
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
corePoolSize
线程池初始化的数量,即使这些线程是闲置的也不会被销毁。
maximumPoolSize
允许在线程池里最大的线程数量。如果用Executors.newCachedThreadPool()创建,默认是Integer.MAX_VALUE可能会堆积请求导致OOM。
keepAliveTime
当线程池线程的数量超过corePoolSize的时候,可以闲置的时间
unit
keepAliveTime的时间单位,天,小时,分钟,毫秒。微秒,纳秒…
workQueue
在任务执行之前,保存任务的队列。
threadFactory
用于创建线程和定义现场的名称。
public class UserThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger nextId = new AtomicInteger(1);
// 定义线程组名称,在问题排查时,非常有帮助
UserThreadFactory(String whatFeaturOfGroup) {
namePrefix = "From UserThreadFactory's " + whatFeaturOfGroup + "-Worker-";
}
@Override
public Thread newThread(Runnable task) {
String name = namePrefix + nextId.getAndIncrement();
Thread thread = new Thread(null, task, name, 0, false);
System.out.println(thread.getName());
return thread;
}
}
handler
已经达到队列的容量时,提交任务的拒绝方式。
BlockingQueue详解
以下都是不能执行的任务存放和获取的方式。
ArrayBlockingQueue
先进先出,阻塞队列,插入元素时队列满了会一直等待。新元素插入到队列的尾部,队列获取操作则是从队列头部开始获得元素。
SynchronousQueue
数组结构的阻塞队列。队列满了以后,任何一次插入操作的元素都要等待相对的删除/读取操作。
LinkedBlockingQueue
先进先出,链表结构非阻塞队列,适合插入和删除较多的操作。
DelayedWorkQueue
延迟队列,延迟的时间还未到的获取的任务会返回空。
PriorityBlockingQueue
优先级队列,元素必须实现Comparable接口,优先级最高的始终在队列的头部,任务会优先执行。
RejectedExecutionHandler详解
以下都是队列满了以后,新任务的处理方式,也可以自己实现RejectedExecutionHandler去自定义。
AbortPolicy
如果线程池队列满了丢掉这个任务并且抛出RejectedExecutionException异常,源码如下:
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString());
}
DiscardPolicy
队列满了任务直接丢掉,什么也不做。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
DiscardOldestPolicy
队列满了以后,移除掉头部的元素,再尝试加入新元素。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
CallerRunsPolicy
队列满了以后,主线程自己去运行。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}