线程池源码实现分析

线程池使用代码:

public static void main(String[] args) {
    ExecutorService service = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 12; i++) {
        service.submit(() -> System.out.println("name " + Thread.currentThread()));
    }
}

主要分析线程池的创建过程和submit()执行过程.

Module One: 创建线程的过程

创建线程池对象
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

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,
                          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;
}

从设计上考虑的话,Executors 是创建线程池对象的工厂类,工厂类设计模式是一种把对象的创建和使用分离的设计模式,工厂类提供对象的创建方法。

  1. corePoolSize 核心线程数,线程池中固定存在的线程数量,空闲时也不会终止。
  2. maximumPoolSize 最大线程数,线程池中允许存在的最大线程的数量,可以是超过 corePoolSize 的数,但是超过的部分,任务执行完后,线程会被终止。
  3. keepAliveTime 超过 corePoolSize 的线程空闲等待任务的最长时间,超过这个时间线程被终止。
  4. workQueue 阻塞队列,任务数超过 corePoolSize 时新来的任务会存放在任务队列中
  5. threadFactory 线程工厂类,用于创建线程
  6. handler 拒绝策略,当核心线程数和队列都满时,处理之后任务的策略
线程池对象参数

主要针对Executors中的一些默认参数做一个举例

workQueue

  1. LinkedBlockQueue
  2. DelayedWorkQueue
  3. SynchronousQueue

RejectedExecutionHandler

  1. AbortPolicy (throw RejectedExecutionException)

线程池的执行过程

Step One: 提交任务

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}
  1. 创建一个 RunnableFuture 对象,这个对象是无返回值的
  2. 执行 RunnableFuture
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

问题一,FutureTask是什么

Step Two: 执行任务

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        reject(command);
}
  1. ctl是一个 AtomicInteger 对象,它由两部分组成,分别是 workerCount 和 runState.
    • 其中 workerCount 代表的是当前线程池内核心线程数内的已启动的线程数,也就是说,当前线程池内的任务超过 corePoolSize 时,workerCount = corePoolSize.
    • runState 有五种状态,后面会再分析
      1. RUNNING: 接收新任务且读取队列中的任务
      2. SHUTDOWN: 不再接收新任务,但是会读取任务队列中的任务
      3. STOP: 停止,不接受新任务且任务队列也不再读取
      4. TIDYING 暂停所有任务,workerCount = 0, thread 会调用 terminated()
      5. TERMINATED terminated() 方法执行完成
  2. 首先会判断 workerCount 是否小于 corePoolSize , 如果是就创建新的线程执行对应的 runnable
  3. 如果现在是 RUNNING 状态且队列未满,则加入队列。加入队列成功后会有一个二次检测的过程,如果当前线程池状态变化,不再是 RUNNING 则要从队列中移除 runnable, 如果状态没变,但是 workerCount = 0, 则创建一些新线程
  4. 队列已满的情况下,判断当前线程数是否小于 maximumPoolSize, 如果小于则创建线程执行任务,否则失败执行拒绝策略。
private boolean addWorker(Runnable firstTask, boolean core) {
    ...
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                int c = ctl.get();
                if (isRunning(c) ||
                    (runStateLessThan(c, STOP) && firstTask == null)) {
                    if (t.getState() != Thread.State.NEW)
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    workerAdded = true;
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}
  1. 省略了一部分代码,主要是对当前线程池的状态做判断
    • 如果当前线程池状态不是 RUNNING 则拒绝接受新的任务
    • 根据core判断是核心线程还是最大线程,超过则返回fasle
  2. 创建一个 Worker 对象,加锁,放到 workers 的 Set 集合中。添加成功调用 thread.start()

Step Three: Worder 对象

Worker 是一个任务执行的类,创建时会有一个FirstTask且会创建一个新的线程,线程执行完FirstTask后会循环从BlockingQueue中取任务执行。

Worker(Runnable firstTask) {
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);
}

public void run() {
    runWorker(this);
}

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted.  This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);
                try {
                    task.run();
                    afterExecute(task, null);
                } catch (Throwable ex) {
                    afterExecute(task, ex);
                    throw ex;
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

主要逻辑就是当前Worker有一个Thread, 这个Thread 会执行FirstTask 和 getTask() 中取到的任务。

private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?
    for (;;) {
        ...
        try {
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

getTask() 中循环从 workQueue 中取任务,这个workQueue就是线程池构造函数中的 blockingQueue. 如果workQueue是 LinkedBlockQueue 那么响应的当队列里面没有内容的时候,workQueue.take() 会阻塞当前线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值