线程池:(可以想象跟银行办理业务场景)【面试】重要
预先创建好一定数量的线程对象,存入缓冲池中,需要用的时候直接从缓冲池中取出,用完之后不要销毁,还回到缓冲池中,为了提高资源的利用率。
优势:提高线程的利用率、提高响应速度、便于统一管理线程对象、可以控制最大的并发数
线程池原理:
1、线程池初始化的时候创建一定数量的线程对象。
2、如果缓冲池中没有空闲的线程对象,则新来的任务进入等待队列
3、如果缓冲池中没有空闲的线程对象,等待队列也已经填满,可以申请再创建一定数量的新线程对象,直到到达线程池的最大值,这时候如果还有新的任务进来,只能选择拒绝。
以上无论哪种线程池,都是工具类Executors封装的,底层代码都一样,都是通过创建ThreadPoolExecutor对象来完成线程池的构建。这几种方式代码不够灵活,无法实现定制化。
/**
* @param corePoolSize 核心池大小,初始化的线程数量 (也就是缓存池大小)
* @param maximumPoolSize 线程池最大线程数,它决定了线程池容量的上限 (其实就是任务量突然增大时候的一种补救措施)
* @param keepAliveTime 线程对象的存活时间(在没有任务可执行的情况下),必须是线程池数量大于核心池才生效
* @param unit 线程对象存活时间单位
* @param workQueue 等待队列,存储等待执行的任务
* @param threadFactory 线程工厂,用来创建线程对象
* @param 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;
}
【描述】:
1、线程池启动的时候会按照核心池的数来创建初始化的线程对象2个。
2、开始分配任务,如果同时来了多个任务,2个线程对象都被占用了,第3个以及之后的任务进入等待队列,当前有线程完成任务恢复空闲状态的时候,等待队列中的任务获取线程对象。
3、如果等待队列也占满了,又有新的任务进来,需要去协调,让线程池再创建新的线程对象,但是线程池不可能无限去创建线程对象,一定会有一个最大上限,就是线程池的最大容量。
4、如果线程池已经达到了最大上限,并且等待队列也占满了,此时如果有新的任务进来,只能选择拒绝,并且需要根据拒绝策略来选择对应的方案。
4种拒绝策略(RejectedExecutionHandler):
1、AbortPolicy:直接抛出异常
2、DiscardPolicy:放弃任务,不抛出异常
3、DiscardOldestPolicy:尝试与等待队列中最前面的任务去争夺,不抛出异常
4、CallerRunsPolicy:谁调用谁处理
超过最大容量时两个重要的异常:AbortPolicy -> RejectedExecutionException 和 CallerRunsPolicy -> 主线程执行
另外new ThreadPoolExecutor.DiscardPolicy() 和 new ThreadPoolExecutor.DiscardOldestPolicy()不会抛出异常
常用的 阻塞队列workQueue:用来存储等待执行的任务
ArrayBlokingQueue:基于数组的先进先出队列,创建时必须指定大小。
LinkedBlockingQueue:基于链表的先进先出队列,创建时可以不指定大小,默认值时Integer.MAX_VALUE.
SynchronousQueue:它不会保存提交的任务,而是直接新建一个线程来执行新来的任务。
PriorityBlockingQueue:具有优先级的阻塞队列。
自定义线程池: