Java线程池--ThreadPoolExecutor学习记录
简介
线程池的使用是为了减少频繁创建线程带来的资源开销,统一管理线程。其中核心线程工具类ThreadPoolExecutor
在多线程当中发挥至关重要的作用。
ThreadPoolExecutor关键父类
1、顶层接口Executor,只提供了void execute(Runnable command)方法执行当前线程
2、第二层接口ExecutorService继承Executor接口,并扩展了一些方法,包括线程终止、提交等等void shutdown()、List<Runnable> shutdownNow()、boolean isShutdown()、 boolean isTerminated()、boolean awaitTermination(long timeout, TimeUnit unit)、<T> Future<T> submit(Callable<T> task)等等
3、第三层抽象类AbstractExecutorService实现ExecutorService接口,并新增了一些方法,包括<T> RunnableFuture<T> newTaskFor(Runnable runnable, T value)、<T> RunnableFuture<T> newTaskFor(Callable<T> callable)等等
4、第四层ThreadPoolExecutor继承AbstractExecutorService类,对线程池真正的操作都在这个核心线程池工具类中,包括创建不同的线程池类型、获取线程池中各个参数、线程池的拒绝策略等等
ThreadPoolExecutor四种构造函数
1、 第一个参数是核心线程池的大小、第二个是最大线程池大小、第三个参数空闲线程存活时间、第四个是时间单位、第五个是缓冲队列,默认调用本地的构造方法使用默认线程工厂和默认的拒绝策略(AbortPolicy-抛出异常)
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
2、 同理,只是指定了创建线程的工厂接口不使用默认的,其他同第一个
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
3、同理,指定了线程拒绝策略,其他同第一个
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
ThreadPoolExecutor构造函数参数说明
1、corePoolSize ---- 核心线程池个数
2、maximumPoolSize ---- 最大线程池个数
3、keepAliveTime ---- 超出核心线程数空闲线程存活时间(依赖第四个参数的值)
4、unit ---- 存活时间单位(毫秒、秒、分、时、天)
5、workQueue ---- 缓冲队列(有界队列ArrayBlockingQueue、无界队列LinkedBlockingQueue(可以指定大小)\SynchronousQueue等等)
6、threadFactory ---- 创建线程的工具接口,有不同的工厂类实现该接口DefaultThreadFactory、 DaemonThreadFactory等等
7、handler ---- 当线程超出最大线程个数时执行的拒绝策略,主要有(AbortPolicy(默认)当线程超出后再有新的线程会抛出异常RejectedExecutionException,DiscardPolicy-直接丢弃没有任何提示,
DiscardOldestPolicy-丢弃最久的线程,CallerRunsPolicy-抛给调用方自行处理)
corePoolSize和maximumPoolSize之间的关系:
1、当前线程小于corePoolSize时,有新的请求进来会立即启动新线程来处理
2、当前线程大于corePoolSize小于maximumPoolSize,会加入缓冲队列中等待
3、当前线程大于maximumPoolSize,有新的请求进来执行拒绝策略
4、当缓冲队列已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务
ThreadPoolExecutor创建不同类型的线程池
1-单例线程池-创建固定线程池大小为1
ExecutorService executor1 = Executors.newFixedThreadPool(1);
ThreadPoolExecutor executor2 = new ThreadPoolExecutor(
1, 1, 0L, TimeUnit.MILLISECONDS
,new LinkedBlockingQueue<>()
,Executors.defaultThreadFactory()
,new ThreadPoolExecutor.AbortPolicy());
2-固定线程池-创建10个固定线程池
ExecutorService executor1 = Executors.newFixedThreadPool(10);
ThreadPoolExecutor executor2 = new ThreadPoolExecutor(
10, 10, 0L, TimeUnit.MILLISECONDS
,new LinkedBlockingQueue<>()
,Executors.defaultThreadFactory()
,new ThreadPoolExecutor.AbortPolicy());
3-可复用线程池
ExecutorService executor1 = Executors.newCachedThreadPool();
ThreadPoolExecutor executor2 = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
4-延迟线程池
ExecutorService executor1 = Executors.newScheduledThreadPool(1);
ThreadPoolExecutor executor2 = new ThreadPoolExecutor(1,
Integer.MAX_VALUE,
0L,NANOSECONDS,
new DelayedWorkQueue<Runnable>());