Java并发编程之美——第八章 Java并发包中线程池ThreadPoolExecutor原理探究

本文深入剖析了Java并发编程中线程池ThreadPoolExecutor的实现原理,包括其内部状态控制、工作线程Worker、任务队列、线程复用和拒绝策略等关键细节。线程池通过高效利用和管理线程,降低了线程创建和销毁的开销,提高了并发性能。
摘要由CSDN通过智能技术生成

Java并发编程之美——第六章 Java并发包中锁原理剖析

Java并发编程之美——第五章 Java并发包中并发List(CopyOnWriteArrayList)源码剖析

Java并发编程之美——第四章 Java并发包中原子操作类原理剖析

Java并发编程之美——第三章 Java并发包中ThreadLocalRandom类原理剖析

Java并发编程之美——第二章 并发编程的其他知识

Java并发编程之美——第一章 Java并发编程基础

Time 2022-01-02——Hireek

介绍

为什么需要线程池?(线程池解决了什么问题?)

  • 当执行大量异步任务时线程池能够提供较好的性能。在不使用线程池时,每当需要执行异步任务时直接new一个线程来运行,而线程的创建和销毁是需要开销的。线程池里面的线程是可复用的,不需要每次执行异步任务时都重新创建和销毁线程。

  • 线程池也提供了一种资源限制和管理的手段,比如可以限制线程的个数,动态新增线程等。

读者也可以自行思考下如何实现线程池?

  • 池化线程
    • 如何创建线程
    • 调度
    • 复用线程
    • 销毁

直接看最核心线程池的实现 ThreadPoolExecutor

ThreadPoolExecutor

类图

在这里插入图片描述

ThreadPool-related class description:

The Executor implementations provided in this package implement ExecutorService, which is a more extensive interface. The ThreadPoolExecutor class provides an extensible thread pool implementation. The Executors class provides convenient factory methods for these Executors.

field

public class ThreadPoolExecutor extends AbstractExecutorService {
  /** The main pool control state, ctl, is an atomic integer packing two conceptual fields workerCount, indicating the effective number of threads runState, indicating whether running, shutting down etc In order to pack them into one int, we limit workerCount to (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2 billion) otherwise representable.*/
  // 原子int,封装了线程数量和状态,高3位表示状态,低29位表示线程池数量 最大(2^29)-1
  private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); 
  private static final int COUNT_BITS = Integer.SIZE - 3;
  // 00011111111111111111111111111111
  private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

  // runState is stored in the high-order bits 
  
  // (高3位) : 11100000000000000000000000000000
  private static final int RUNNING    = -1 << COUNT_BITS;
  // (高三位) : 00000000000000000000000000000000
  private static final int SHUTDOWN   =  0 << COUNT_BITS;
  // (高三位) : 00100000000000000000000000000000
  private static final int STOP       =  1 << COUNT_BITS;
  // (高三位) : 01000000000000000000000000000000
  private static final int TIDYING    =  2 << COUNT_BITS;
  // (高三位) : 01100000000000000000000000000000
  private static final int TERMINATED =  3 << COUNT_BITS;

  // 保存任务的阻塞队列
  private final BlockingQueue<Runnable> workQueue;

  // 锁
  private final ReentrantLock mainLock = new ReentrantLock();

  /**
     * Set containing all worker threads in pool. Accessed only when
     * holding mainLock.
     */
  private final HashSet<Worker> workers = new HashSet<Worker>();

  /**
     * Wait condition to support awaitTermination
     */
  private final Condition termination = mainLock.newCondition();

  /**
     * Tracks largest attained pool size. Accessed only under
     * mainLock.
     */
  private int largestPoolSize; // tracks 跟踪当前线程池的线程(已经存在的)的最大值。

  /**
     * Counter for completed tasks. Updated only on termination of
     * worker threads. Accessed only under mainLock.
     */
  private long completedTaskCount;

  // Factory for new threads. All threads are created using this factory (via method addWorker).
  // 默认实现DefaultThreadFactory
  private volatile ThreadFactory threadFactory;

  /**
     * 拒绝策略
     */
  private volatile RejectedExecutionHandler handler;

  // 存活时间
  private volatile long keepAliveTime;

  /**
     * If false (default), core threads stay alive even when idle.
     * If true, core threads use keepAliveTime to time out waiting
     * for work.
     */
  private volatile boolean allowCoreThreadTimeOut;

  /**
     * Core pool size is the minimum number of workers to keep alive
     * (and not allow to time out etc) unless allowCoreThreadTimeOut
     * is set, in which case the minimum is zero.
     */
  private volatile int corePoolSize;
 
  /**
     * Maximum pool size. Note that the actual maximum is internally
     * bounded by CAPACITY.
     */
  private volatile int maximumPoolSize; // 线程池允许创建线程的最大值
}

Worker——private final class

private final class Worker
  extends AbstractQueuedSynchronizer
  implements Runnable {
  /**
     * This class will never be serialized, but we provide a
     * serialVersionUID to suppress a javac warning.
     */
  private static final long serialVersionUID = 6138294804551838833L;

  /** Thread this worker is running in.  Null if factory fails. */
  final Thread thread;
  /** Initial task to run.  Possibly null. */
  Runnable firstTask;
  /** Per-thread task counter */
  volatile long completedTasks;

  /**
     * Creates with given first task and thread from ThreadFactory.
     * @param firstTask the first task (null if none)
     */
  Worker(Runnable firstTask) {
    // 在构造函数内首先设置Worker的状态为-1,这是为了避免当前Worker在调用rnnWorker方法前被中断
    // (当其他线程调用了线程池的shutdownNow时,如果Worker状态>=O则会中断该线程)。
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);
  }

  /** Delegates main run loop to outer runWorker  */
  public void run() {
    runWorker(this);
  }
}

public void execute(Runnable command)

注释已经很明白了,就不讲了。

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    /*
     * Proceed in 3 steps:
     *
     * 1. If fewer than corePoolSize threads are running, try to
     * start a new thread with the given command as its first
     * task.  The call to addWorker atomically checks runState and
     * workerCount, and so prevents false alarms that would add
     * threads when it shouldn't, by returning false.
     *
     * 2. If a task can be successfully queued, then we still need
     * to double-check whether we should have added a thread
     * (because existing ones died since last checking) or that
     * the pool shut down since entry into this method. So we
     * recheck state and if necessary roll back the enqueuing if
     * stopped, or start a new thread if there are none.
     *
     * 3. If we cannot queue task, then we try to add a new
     * thread.  If it fails, we know we are shut down or saturated
     * and so reject the task.
     */
    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(); // recheck
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        reject(command);
}

主要分析下addWorker

private boolean addWorker(Runnable firstTask, boolean core)

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN && // !SHUTDOWN
               firstTask == null && // SHUTDOWN && firstTask!=null
               ! workQueue.isEmpty())) // SHUTDOWN && workQueue.isEmpty()
            return false;
				// for(;;) compareAndIncrementWorkerCount
        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  // Re-read ctl
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }

    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;
          	// 加独占锁,为了实现workers同步,因为可能多个线程调用了线程池的execute方法
            mainLock.lock();
            try {
                // Recheck while holding lock.
                // Back out on ThreadFactory failure or if
                // shut down before lock acquired.
              
              	// 重新检查线程池状态,以避免在获取锁前调用了shutdown
                int rs = runStateOf(ctl.get());

                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) { // shutdown状态还可能会添加新的线程,继续执行队列中任务
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
              	// 释放锁
                mainLock.unlock();
            }
            if (workerAdded) {
                t.start(); // 启动线程!
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

final void runWorker(Worker w)

 /**
     * Main worker run loop.  Repeatedly gets tasks from queue and
     * executes them, while coping with a number of issues:
     */
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) { // getTask
          	// 加锁是为了避免在任务运行期间,其他线程调用了shutdown后正在执行的任务被中断(shutdown只会中断当前被阻塞挂起的线程)
            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);
                Throwable thrown = null;
                try {
                    task.run();
                } catch (RuntimeException x) { // catch e 防止线程死亡
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

当然还有getTask()、shutdown()等源码待研究。具体的拒绝策略…

总结

线程池巧妙地使用一个Integer类型的原子变量来记录线程池状态和线程池中的线程个数。通过线程池状态来控制任务的执行,每个Worker线程可以处理多个任务。线程池通过线程的复用减少了线程创建和销毁的开销。还是比较巧妙的。

参考

  • java并发编程之美

  • https://www.cnblogs.com/liuzhihu/p/8177371.html

加油,温润自己的心!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值