ThreadPoolExecutor 源码解析

在阿里巴巴的《Java开发手册》中是这样规定线程池的:

线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的读者更加明确线程池的:

线程池不允许使用Executors 去创建,而是通过ThreadPoolExecutor 的方式创建的,这样的处理方式程序员更加明确线程池的运行规则.避免资源耗尽的风险.

说明:Executors返回的线程池对象的弊端如下:

1)FixedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量请求,从而导致OOM

2) CachedThreadPool 和 ScheduledThreadPool: 允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量线程,从而到时OOM

其实当我们去看Executors的源码会发现,Executors.newFixedThreadPool()、Executors.newSingleThreadExecutor()和Executors.newCachedThreadPool等方法的底层都是通过ThreadPoolExecutor 实现的.



public class Executors {

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
   
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    
    // 那构造器最全的参数举例
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            // maximumPoolSize 必须大于0,且必须大于  corePoolSize 
            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;
    }

}

   1.  int corePoolSize : 标识线程池的常驻核心线程数.

                                    如果等于0,则标识在没有任何任务的时候,销毁线程池.

                                    如果大于0 ,即使没有任务时,也会保证线程池的线程数量等于次值. 但需要注意的是,如果此值设置的比较小,

                                    则会频繁创建和销毁线程

                                    如果设置的比较大,则会浪费系统资源,所以程序要需要根据自己的实际业务来调整此值.

 2. int maximumPoolSize :表示线程池在任务最多时,最大可以创建的线程数.

                                       官方规定此值必须大于0,同时也必须大于 corePoolSize, 此值只有在任务比较多的时候,且不能存放在任                                           务队列时,才会用到.

3. long keepAliveTime: 表示线程的存活时间,当线程池空闲时并且超过了此时间,多余的线程就会销毁,直到线程池中的线程数量销毁等于corePoolSize为止.

                                如果 maximumPoolSize 等于corePoolSize,那么线程池在空闲的时候,也不会销毁任何线程.

4.TimeUnit unit : 表示存活时间的单位,它是配合keepAliveTime 参数共同使用的

5.BlockingQueue<Runnable> workQueue :表示线程池执行的任务队列,当线程池的所有线程都在处理任务时,如果来了新任务会缓存到此任务队列中排队等待执行.

6.ThreadFactory threadFactory: 表示线程的创建工厂,这个参数一般用的比较少,我们通常在创建线程时不指定此参数,它会使用默认的线程创建工厂的方法来创建线程



 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
  }

  public static ThreadFactory defaultThreadFactory() {
        return new DefaultThreadFactory();
  }

  // 默认的线程创建工厂,需要创建ThreadFactory 
  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;
        }
    }

7.RejectedExecutionHandler handler: 表示指定线程池的拒绝策略. 当线程池的任务已经在缓存队列 workQueue  中存储满了之后,并且不能创建新的线程来执行此任务时,就会用到此拒绝策略,它属于一种限流保护机制. 

ThreadPoolExecutor 自带了4中拒绝策略:

new ThreadPoolExecutor.AbortPolicy():终止策略,线程池会抛出异常并终止执行,它是默认的拒绝策略.
new ThreadPoolExecutor.CallerRunsPolicy():报任务提交给当前线程来执行
new ThreadPoolExecutor.DiscardPolicy(): 忽略此任务(最新的任务)
new ThreadPoolExecutor.DiscardOldestPolicy():忽略最早的任务(最先加入队列的任务)

通过看源码以上4种拒绝策略均实现了RejectedExecutionHandler ,因此要自定义拒绝策略:

public interface RejectedExecutionHandler {
     void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

也应该实现该接口就可以了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章