本文详解 ThreadPoolExecutor 类
构造方法:
// 1.8 源码 JDK 注释
public ThreadPoolExecutor(
int corePoolSize,
// the number of threads to keep in the pool, even if they are idle, unless is set
// 保持在池中的线程数量,即是他们空闲也在池中,除非设置他们. ----核心线程数量.
int maximumPoolSize,
// the maximum number of threads to allow in the pool
// 池中允许的最大线程数
long keepAliveTime,
// when the number of threads is greater than the core, this is the maximum time that
// excess idle threads will wait for new tasks before terminating.
// 当线程数大于核心时,多余空闲线程在终止之前等待新任务的最长时间.
TimeUnit unit,
// the time unit for the argument
// 等待的时间单位
BlockingQueue<Runnable> workQueue,
// the queue to use for holding tasks before they are executed. This queue will hold
// only the tasks submitted by the method.
// 在执行任务之前用于保存任务的队列。 此队列仅包含该方法提交的任务。
ThreadFactory threadFactory,
// 线程工厂
RejectedExecutionHandler handler) {} // 拒绝策略
运行机制:
通过 new 创建线程池时, 除非调用 prestartAllCoreThreads / prestartCoreThread 方法启动核心线程,
否则即使工作队列中存在任务,同样也不会执行.
/**
* -通过 new 创建线程池时, 除非调用 prestartAllCoreThreads / prestartCoreThread 方法启动核心线程,
* -否则即使工作队列中存在任务,同样也不会执行.
*/
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(8, 20, 3L, TimeUnit.SECONDS, linkedBlockingDeque);
/**
* Starts all core threads, causing them to idly wait for work. This
* overrides the default policy of starting core threads only when
* new tasks are executed.
* -启动所有核心线程,让它们无空闲的等待工作。 这将覆盖仅在执行新任务时启动核心线程的默认策略。
* -手动启动线程池.
* @return the number of threads started
*/
threadPoolExecutor.prestartAllCoreThreads();
RejectedExecutionHandler:(详见JDK源码)
实现类:
AbortPolicy : 默认, 中止策略,直接抛 RejectedExecutionException(拒绝执行异常.)
AbortPolicyWithReport: 中止时记录警告信息. 它是上面策略的子类.
CallerRunsPolicy : 只要线程池没有关闭. 让当前线程直接执行被丢弃的任务.
DiscardPolicy : 什么都不干, 直接丢弃任务.
DiscardOldestPolicy : 丢弃最老的一个请求(任务队列里第一个),再尝试提交任务.
线程池的使用建议:
避免使用 Executor 框架去创建线程池.
newFixedThreadPool newSingleThreadExecutor
允许的请求队列长度为 Integer.MAX_VALUE, 可能会堆积大量的请求, 从而导致OOM.
这个会撑爆你设置的项目内存.
newCachedThreadPool newScheduledThreadPool
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
这个会撑爆你整台服务器还剩的可用内存.不依赖你设置的项目内存.
核心线程数量不要太大.
要处理异常.
/* 1. execute 没有返回值.
* submit 有返回值
* 2. execute 直接抛出异常
* submit 如果发生异常,不会直接抛出,而是在返回值里get才会抛出.
*/
/**
* - 测试 submit 和 execute 的区别
* @author
* @date
*/
public class Submit_Execute {
public static void main(String[] args) throws InterruptedException, ExecutionException {
BlockingQueue<Runnable> linkedBlockingDeque = new LinkedBlockingDeque<>(64);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(4, 8, 3L, TimeUnit.SECONDS, linkedBlockingDeque);
try {
for (int i = 0; i < 32; i++) {
Future<?> submit = threadPoolExecutor.submit(() -> {
System.out.println(Thread.currentThread().getName());
return Integer.parseInt("abc");
});
submit.get();
}
} finally {
threadPoolExecutor.shutdown();
}
/* 1. execute 没有返回值.
* submit 有返回值
* 2. execute 直接抛出异常
* submit 如果发生异常,不会直接抛出,而是在返回值里get才会抛出.
*/
}
}