This page looks best with JavaScript enabled

线程池ThreadExexutor原理与使用

 ·  ☕ 3 min read

ThreadPoolExecutor组成

ThreadPoolExecutor的核心构造函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
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:线程池最大能容纳的线程数(实际是当核心线程池满了之后会进行扩容maxSize - coreSize)
  3. keepAliveTime: 当线程执行完毕之后等待被销毁的时间
  4. workQueue:存放等待执行的 Runnable,是一个BlockingQueue。
  5. ThreadFactory: 线程的构造方法
  6. RejectedExecutionHandler: 线程被拒绝加入线程池时执行的策略

等待队列 BlockingQueue

  • ArrayBlockingQueue : 基于数组的先进先出队列,构造时必须指明大小;
  • LinkedBlockingDeque : 基于链表的队列,如果构造时没有指明大小,则默认为Integer.MAX_VALUE;
  • SynchronousQueue : 一次只会执行一个元素的队列, 新加入元素的操作会被阻塞到已有元素出队之后;

线程池原理

线程池的策略,当来新线程时:

  1. 如果线程池中有空闲线程,就复用空闲线程。
  2. 如果没有空闲线程,就将新 Runnable 加入等待队列。
  3. 如果来的 Runnable 太多,等待队列也满了,就临时扩容到maxPoolSize,相当于使用了一个临时线程池来使用。
  4. 如果扩容还是无法满足,就执行拒绝策略。具体的拒绝策略根据创建时的handler决定。
  5. 线程池通过Woker中的线程循环从等待队列中获取 Runnable 执行来避免重复创建新线程。

ThreadPoolExecutor用法

1. 直接实例化一个

1
2
3
4
5
6
7
8
9
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), handler);
}

2. 使用Executorsnew****Pool()方法创建ExecutorService:

每一个 newXxxxPool 方法实质也是调用 ThreadPoolExecutor 的构造方法,只是传入的参数是设定好的。

1
2
3
4
5
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
  • FixedThreadPool : 核心线程池大小和最大线程池一样,缓存队列为LinkedBlokingQueue,超出线程池满了之后进入的线程都会被加入等待队列。
  • ScheduledThreadPool : 核心线程池大小用户决定,最大线程池大小为Integer.MAX_VALUE。等待队列为:DelayedWorkQueue
  • SingleThreadExecutor : 核心线程池为0,意味着新的线程马上就会被创建。

ThreadPoolExecutor和ExecutorService的区别

Executor ExecutorService

首先ExecutorExecutorService都是接口,ThreadPoolExecutor是类。

通过Executors.new****Pool创建线程池返回的都是ExecutorService的实例,相当于是调用的ThreadPoolExecutor的构造方法,返回的是它的父类AbstracExecutorService的实例。AbstracExecutorService又是实现了ExecutorService接口的抽象类。

Support the author with
alipay QR Code
wechat QR Code

Yang
WRITTEN BY
Yang
Developer