(手机横屏看源码更方便)java
注:java源码分析部分如无特殊说明均基于 java8 版本。面试
ThreadPoolExecutor的构造方法是建立线程池的入口,虽然比较简单,可是信息量很大,由此也能引起一系列的问题,一样地,这也是面试中常常被问到的问题,下面彤哥只是列举了一部分关于ThreadPoolExecutor构造方法的问题,若是你都能回答上来,则能够不用看下面的分析了。安全
(1)ThreadPoolExecutor有几个构造方法?并发
(2)ThreadPoolExecutor最长的构造方法有几个参数?工具
(3)keepAliveTime是作什么用的?源码分析
(7)核心线程会不会超时关闭?能不能超时关闭?ui
(4)ConcurrentLinkedQueue能不能做为任务队列的参数?this
(5)默认的线程是怎么建立的?google
(6)如何实现本身的线程工厂?.net
(7)拒绝策略有哪些?
(8)默认的拒绝策略是什么?
好了,咱们直接上代码。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler); } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), handler); } 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.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
ThreadPoolExecutor有四个构造方法,其中前三个最终都是调用最后一个,它有7个参数,分别为corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。
核心线程数。
当正在运行的线程数小于核心线程数时,来一个任务就建立一个核心线程;
当正在运行的线程数大于或等于核心线程数时,任务来了先不建立线程而是丢到任务队列中。
最大线程数。
当任务队列满了时【本篇文章由公众号“彤哥读源码”原创】,来一个任务才建立一个非核心线程,但不能超过最大线程数。
线程保持空闲时间及单位。
默认状况下,此两参数仅当正在运行的线程数大于核心线程数时才有效,即只针对非核心线程。
可是,若是allowCoreThreadTimeOut被设置成了true,针对核心线程也有效。
即当任务队列为空时,线程保持多久才会销毁,内部主要是经过阻塞队列带超时的poll(timeout, unit)方法实现的。
任务队列。
当正在运行的线程数大于或等于核心线程数时,任务来了是先进入任务队列中的。
这个队列必须是阻塞队列,因此像ConcurrentLinkedQueue就不能做为参数,由于它虽然是并发安全的队列,可是它不是阻塞队列。
// ConcurrentLinkedQueue并无实现BlockingQueue接口 public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> implements Queue<E>, java.io.Serializable { // ...【本篇文章由公众号“彤哥读源码”原创】 }
线程工厂。
默认使用的是Executors工具类中的DefaultThreadFactory类,这个类有个缺点,建立的线程的名称是自动生成的,没法自定义以区分不一样的线程池,且它们都是非守护线程。
static class DefaultThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } }
那怎么自定义一个线程工厂呢?
其实也很简单,本身实现一个ThreadFactory,而后把名称和是不是守护进程看成构造方法的参数传进来就能够了。
有兴趣的同窗能够参考netty中的默认线程工厂或者google中的线程工厂。
io.netty.util.concurrent.DefaultThreadFactory com.google.common.util.concurrent.ThreadFactoryBuilder
拒绝策略。
拒绝策略表示当任务队列满了且线程数也达到最大了,这时候再新加任务,线程池已经没法承受了,这些新来的任务应该按什么逻辑来处理。
经常使用的拒绝策略有丢弃当前任务、丢弃最老的任务、抛出异常、调用者本身处理等待。
默认的拒绝策略是抛出异常,即线程池没法承载了,调用者再往里面添加任务会抛出异常。
默认的拒绝策略虽然比较简单粗暴,可是相对于丢弃任务策略明显要好不少,最起码调用者本身能够捕获这个异常再进行二次处理。
OK,ThreadPoolExecutor的构造方法这块咱们今天进行了深刻解析,关于这块,您还有什么问题呢?欢迎留言评论、私聊勾搭。
欢迎关注个人公众号“彤哥读源码”,查看更多源码系列文章, 与彤哥一块儿畅游源码的海洋。