初识ThreadPoolExecutor(二)——源码简单解读

二、ThreadPoolExecutor源码简单解读

1.execute方法
execute方法继承自Executor,是线程池的核心方法,公共入口,用于将一个任务提交至线程池,并为其安排处理方式。
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))  //I
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) { //II
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))  //III
                reject(command);  //IV
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);  //IV
    }
I - 当运行线程数小于线程池基本大小时(workerCountOf© < corePoolSize),新增一个线程用以处理新提交的任务。
II - 如果线程池处于运行状态,且工作队列未满,则将任务加入工作队列后不作任何操作。
III - 如果当前线程池不在运行状态( isRunning(recheck)==false),则将该任务从工作队列中移除(remove(command)),并且尝试关闭线程池(tryTerminate())。移除过程中将调用terminated方法。
 public boolean remove(Runnable task) {
        boolean removed = workQueue.remove(task);
        tryTerminate(); // In case SHUTDOWN and now empty
        return removed;
    }
    
IV - 在II的基础上移除成功后,将调用饱和政策(即上一篇所说的,线程池关闭时,也将启用饱和政策)。 或者工作队列已满(workQueue.offer(command)==false)并且新增线程失败(addWorker(command, false)==false),也将启用饱和政策。
/**
     * Invokes the rejected execution handler for the given command.
     * Package-protected for use by ScheduledThreadPoolExecutor.
     */
    final void reject(Runnable command) {
        handler.rejectedExecution(command, this);
    }

2.addWorker方法
addWorker方法尝试新增一个线程用来处理新任务。
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 &&
                   firstTask == null &&
                   ! workQueue.isEmpty())) //I
                return false;

            for (;;) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize)) //II
                    return false;
                if (compareAndIncrementWorkerCount(c))  //III
                    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; //IV
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        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(); //V
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }
I - 判断线程池状态,不符合则不进行新增线程操作,直接返回false。
II - 根据入参core进行判断,如果已启动线程数量大于相应容量(基本大小/最大大小),则不进行新增线程操作,直接返回false。
III - 以上验证均通过之后,将更新已启动线程数等数据,然后跳出retry循环。若数据更新失败,则continue。
IV - 该Thread由ThreadFactory创建,具体实现如下:
    Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
    }
V - 启动线程。
3.Worker对象
当任务提交到线程池之后,并且需要创建新的线程时,将会先把任务提交到Worker的构造器,用以创建一个worker对象。
worker持有一个线程对象,该对象为线程池中的基本线程对象,即所有任务都是通过此种线程进行处理的。且该线程对象通过this.thread = getThreadFactory().newThread(this)进行获取。
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) {
            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);
        }

        // Lock methods
        //
        // The value 0 represents the unlocked state.
        // The value 1 represents the locked state.

        protected boolean isHeldExclusively() {
            return getState() != 0;
        }

        protected boolean tryAcquire(int unused) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        protected boolean tryRelease(int unused) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        public void lock()        { acquire(1); }
        public boolean tryLock()  { return tryAcquire(1); }
        public void unlock()      { release(1); }
        public boolean isLocked() { return isHeldExclusively(); }

        void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }
    }
4.runWorker方法
线程池中线程对象运行时,实际将会调用worker对象的run方法,进一步调用runWorker方法。runWorker方法持有一个循环语句——当worker对象携带了初始任务(线程刚创建)或者还能从任务队列中获取到任务时(task = getTask())!= null),将会在此线程中调用任务的run方法,执行操作。当无法获取到需要执行的任务时,线程将会调用processWorkerExit方法尝试关闭自己。
值得注意的是,beforeExecute与afterExecute都将在此方法中被调用。
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);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        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);
        }
    }
5.getTask方法
getTask方法将从工作队列中获取待执行的任务,若该方法返回null,则runWorker方法中while循环将结束,进而线程run方法结束,即调用该方法的工作线程将会被关闭。
private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            } //I

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c)) //II
                    return null;
                continue;
            }

            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take(); //III
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }
I - 已经关闭,或者调用了shutdown方法并且工作队列为空时,将会返回null。
II - 在工作队列不为空,并且已启动线程数量大于一的前提下,已启动线程大于最大线程(wc > maximumPoolSize,当线程池运行之后,再调用setMaximumPoolSize方法设置线程池最大大小可能会导致此种情况)或者启用超时关闭线程(timed==true,当设置了allowCoreThreadTimeOut=true或者已启动线程数大于线程池基本大小时)并且上次尝试获取任务超时(timedOut = true)的情况将会返回null。
III - 获取任务,当不需要关闭线程时,此方法将一直阻塞直到获取到新的任务。否则,根据构造线程池时传入的失效时间调用限时的poll方法,规定时间内未获取到任务,则代表该线程处于空闲状态。将通过II返回null。
6.processWorkerExit方法
processWorkerExit方法将移除一个从当前workers中移除该worker(workers.remove(w))并且尝试关闭线程池。在此之后,若是该线程是由于运行时抛出了不受检异常或错误而关闭(completedAbruptly==true)、或者任务队列不为空缺无工作线程、或是基本线程不允许标记超时并且已启动线程少于线程池基本大小时,将会重新增加一个线程(addWorker(null, false))。
 private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks;
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }

        tryTerminate();

        int c = ctl.get();
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false);
        }
    }
7.tryTerminate方法
该方法将在execute方法检测出线程池不处于runing状态与调用processWorkerExit方法退出一个线程之后被调用。用于尝试关闭整个线程池。此方法中将调用可拓展的terminated方法。
final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))//如果线程池尚未终止,则直接返回
                return;
            if (workerCountOf(c) != 0) { // Eligible to terminate
                interruptIdleWorkers(ONLY_ONE);//中断一个线程
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();
                    } finally {
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThreadPoolExecutor 是 Java 中用于管理线程池的类,它实现了 ExecutorService 接口。它可以帮助我们更方便地管理和调度多线程任务的执行。 下面是 ThreadPoolExecutor 的原理概述: 1. 构造函数:ThreadPoolExecutor 的构造函数接收一些参数,包括核心线程数、最大线程数、任务队列、线程工厂、拒绝策略等。通过这些参数,我们可以配置线程池的大小和行为。 2. 核心线程池:ThreadPoolExecutor 会首先创建核心线程池。核心线程池中的线程数量不会超过核心线程数的设定,即使线程处于空闲状态也不会被回收。 3. 任务队列:当提交一个任务时,如果核心线程池已满,任务会被放入任务队列中等待执行。ThreadPoolExecutor 提供了多种类型的任务队列,如无界队列和有界队列等,可以根据需求进行选择。 4. 最大线程数控制:当任务队列已满时,ThreadPoolExecutor 会根据最大线程数的设定来创建新的线程,直到达到最大线程数。超过最大线程数的任务将会根据指定的拒绝策略进行处理。 5. 执行任务:当有任务可执行时,ThreadPoolExecutor 会从任务队列中取出任务,并将其交给一个空闲的线程执行。如果核心线程池中的线程都在执行任务,新的任务会被放入任务队列中等待。 6. 拒绝策略:当任务队列已满且达到最大线程数时,ThreadPoolExecutor 会根据指定的拒绝策略来处理无法执行的任务。常见的拒绝策略有抛出异常、丢弃任务等。 以上是 ThreadPoolExecutor 的基本原理概述。详细的码实现可以参考 Java SDK 的码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值