JDK自定义的ThreadPoolExecutor类中四种线程池的分析

1. ThreadPoolExecutor线程池的七大参数

这里直接上ThreadPoolExecutor线程池构造器的源码

//1.corePoolSize-线程池中的核心线程数
//2.maximumPoolSize-线程池中允许的最大线程数,当核心线程数占满后,若最大线程数还未满,则启动非核心线程
//3.keepAliveTime-超时时间,当线程数大于核心线程数,这是多余线程也就是非核心线程在等待新任务的最长时间
//4.unit – keepAliveTime参数的时间单位
//5.workQueue-用于执行任务之前保存任务的队列,这个队列只保存Executor接口中execute提交的Runnable任务
//6.threadFactory-执行程序时创建线程的工厂
//7.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;
    }

理论上:当任务Runnable来时,会优先使用核心线程执行该任务,若核心线程都被使用,则新来的任务进入任务队列等待执行,若任务队列满了,则非核心线程执行该任务,若非核心线程也满了,若又有新任务来了,此时任务队列和线程数都满了,则执行拒绝策略

2. Executors.newCachedThreadPool()

Executors,JDK提供的一个创建线程池的类

 public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
 }

CachedThreadPool线程池的核心线程数为0,最大线程数为2147483647,超时时间为60s,任务队列为SynchronousQueue
当达到一分钟, 未使用的线程将被终止并从缓存中删除,该线程池的任务队列SynchronousQueue为一个阻塞队列,没有容量,每个线程的插入操作都需要等待下一个线程的移除操作,类似用手传递东西,你不拿,东西就一直在上一个人手里,即来一个任务就创建一个非核心线程接收,然后放进缓存中,若超过60s,该线程未使用,则从缓存里删除。

3.Executors.newFixedThreadPool(int cpuCoreNum)

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

固定线程线程池,该线程的的最大线程数等于核心线程数,无超时时间,而任务队列LinkedBlockingQueue又是个未指定的边界的有界阻塞队列(默认容量为Integer.MAX_VALUE)基于链表实现的。 该队列对元素 FIFO(先进先出)进行排序。 队列的头部是在队列中停留时间最长的那个元素。 队列的尾部是在队列中停留时间最短的那个元素。由于该线程中的线程都是核心线程,即任务一来,核心线程执行该任务,核心线程一满,多余任务去LinkedBlockingQueue阻塞队列中等待执行,无超时时间,也就无拒绝策略。该线程池可以让任务并行执行(核心线程跑在CPU的内核上),多个核心线程即在不同的内核上并行执行。

补充:由于任务队列的不同,LinkedBlockingQueue的容量适合处理任务量多的场景而SynchronousQueue适合的场景较普遍,由于无容量,靠非核心线程执行然后缓存。
可以得出:

  • 任务量平稳用–》FixedThreadPool
  • 任务量不平稳用–》CacheThreadPool

4.Executors.newSingleThreadExecutor()

  public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

单一线程线程池,该线程池中的线程只有一个核心线程,无超视时间,任务队列也是有界的基于链表实现的阻塞队列,先进先出,让一个程序串行执行任务,保证了任务的执行顺序。

5.Executors.newScheduledThreadPool(int corePoolSize)

  public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

定时任务线程池,可指定核心线程数,最大线程数为2147483647,无超时时间,任务队列为延时队列,可以指定每个任务间隔多长时间执行,如:

public class TestScheduledThreadPool {
    public static void main(String[] args) {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
        /**
         * 隔多长时间执行一次
         */
        service.scheduleAtFixedRate(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
        //initialDelay:第一个任务执行之前需要延迟多长时间,period:间隔多长时间
        }, 0, 500, TimeUnit.MILLISECONDS);

    }
}

6.后言

本文作为复习线程池时的知识整理,为了面试心里不慌。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值