创建方式
ThreadPoolExecutor(推荐)
七大参数:
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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
Executor(不推荐)
原因:本质还是ThreadPoolExecutor
FixedThreadPool 和 SingleThreadExecutor : 使用的是无界的 LinkedBlockingQueue,任务队列最大长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致 OOM。
CachedThreadPool :使用的是同步队列 SynchronousQueue, 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致 OOM。
ScheduledThreadPool 和 SingleThreadScheduledExecutor : 使用的无界的延迟阻塞队列DelayedWorkQueue,任务队列最大长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致 OOM。
工作方式
线程在有任务的时候会创建核心线程数corePoolSize
当线程满了(有任务但是线程被使用完)不会立即扩容,而是放到阻塞队列中,当阻塞队列满了之后才会继续创建线程。
如果队列满了,线程数达到最大线程数则会执行拒绝策略。
当线程数大于核心线程数时,超过KeepAliveTime(闲置时间),线程会被回收,最终会保持corePoolSize个线程。
拒绝策略
ThreadPoolExecutor.AbortPolicy: 抛出 RejectedExecutionException来拒绝新任务的处理。
ThreadPoolExecutor.CallerRunsPolicy: 调用执行自己的线程运行任务,也就是直接在调用execute方法的线程中运行(run)被拒绝的任务,如果执行程序已关闭,则会丢弃该任务。因此这种策略会降低对于新任务提交速度,影响程序的整体性能。如果可以承受此延迟并且要求任何一个任务请求都要被执行,可以选择此策略。
ThreadPoolExecutor.DiscardPolicy: 不处理新任务,直接丢弃掉。
ThreadPoolExecutor.DiscardOldestPolicy: 此策略将丢弃最早的未处理的任务请求。
应用场景
最大线程池大小
CPU 密集型任务(N+1): 利用 CPU 计算能力的任务
I/O 密集型任务(2N): 网络读取,文件读取
Future & Callable
Future:将任务交给子线程执行,Future<TASK>
FutureTask实现了 Future接口,可传入 Callable 或者 Runnable 对象
CompletableFuture:解决了Future一些局限性比如不支持异步任务的编排组合、获取计算结果的 get() 方法为阻塞调用等,主要是靠CompletionStage接口里面维护的大量函数式编程