Java Concurrent Programming: addWorker method of ThreadPoolExecutor

Posted by ksb24930 on Sun, 03 Nov 2019 15:32:00 +0100

From: https://blog.csdn.net/u011637069/article/details/79593114

addWorker method

The source code is relatively long and looks bluff. In fact, I did two things. 1) only use cyclic CAS operation to increase the number of threads by 1; 2) create a new thread and enable it.

The source code is as follows:

        private boolean addWorker (Runnable firstTask,boolean core){
            //(1)loop CAS Operation, changing the number of threads in the thread pool+1.
            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()))
                    return false;

                for (; ; ) {
                    int wc = workerCountOf(c);
                    //core true To add threads to the core thread pool false Represents adding threads to the maximum thread pool
                    //The number of threads exceeds the limit. It can't be added any more. Return directly
                    if (wc >= CAPACITY ||
                            wc >= (core ? corePoolSize : maximumPoolSize))
                        return false;
                    //CAS modify clt Value+1,Free space in the thread pool for the thread to be added, exit successfully cas Loop, fail to continue
                    if (compareAndIncrementWorkerCount(c))
                        break retry;
                    c = ctl.get(); // Re-read ctl
                    //If the state of the thread pool changes back to retry Outer circulation
                    if (runStateOf(c) != rs)
                        continue retry;
                    // else CAS failed due to workerCount change; retry inner loop
                }
            }
            //(2)Create a new thread and join it to the thread pool workers Medium.
            boolean workerStarted = false;
            boolean workerAdded = false;
            Worker w = null;
            try {
                //Yes workers The operation should be realized by locking
                final ReentrantLock mainLock = this.mainLock;
                w = new Worker(firstTask);
                final Thread t = w.thread;
                if (t != null) {
                    //Refine the strength of lock to prevent excessive critical area and waste of time
                    mainLock.lock();
                    try {
                        // Recheck while holding lock.
                        // Back out on ThreadFactory failure or if
                        // shut down before lock acquired.
                        int c = ctl.get();
                        int rs = runStateOf(c);
                        //Determine the status of thread pool
                        if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
                            //Judge the added task status,If you start throwing exceptions
                            if (t.isAlive()) // precheck that t is startable
                                throw new IllegalThreadStateException();
                            //Add a new thread to the thread pool
                            workers.add(w);
                            int s = workers.size();
                            //correct largestPoolSize Value
                            if (s > largestPoolSize)
                                largestPoolSize = s;
                            workerAdded = true;
                        }
                    } finally {
                        mainLock.unlock();
                    }
                    //If the thread pool is added successfully, the newly created thread will be opened
                    if (workerAdded) {
                        t.start();//(3)
                        workerStarted = true;
                    }
                }
            } finally {
                //Thread failed to add thread pool or thread start Failed, you need to call addWorkerFailed Function,
                //If the addition is successful, you need to remove it and reply clt Value
                if (!workerStarted)
                    addWorkerFailed(w);
            }
            return workerStarted;
        }


logic analysis

 

Class Worker

Inherited from AQS, it has the function of lock, realizes the Runable interface, and has the function of thread.

        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;

            //Threads that are running in the thread pool. Created by the thread factory we specified
            final Thread thread;
            //Thread wrapped task. thread stay run The run Method
            Runnable firstTask;
            //Record the number of tasks completed by the current thread
            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;
                //Create a thread using the thread factory we specified
                this.thread = getThreadFactory().newThread(this);
            }

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

According to the source code, the run method of the Worker class actually calls the runworker method of ThreadPoolExecutor. Next, I'll take a look at the runworker source code and annotation parsing of the ThreadPoolExecutor.

        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();
                    //Thread pool in stop State or when the current thread is interrupted, the thread pool state is stop Status.
                    //If the current thread is not interrupted, an interrupt request will be issued
                    if ((runStateAtLeast(ctl.get(), STOP) ||
                            (Thread.interrupted() &&
                                    runStateAtLeast(ctl.get(), STOP))) &&
                            !wt.isInterrupted()) {
                        wt.interrupt();
                    }

                    try {
                        //Before starting the task Hook,Similar to callback function
                        beforeExecute(wt, task);
                        Throwable thrown = null;
                        try {
                            //Perform tasks
                            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 {
                            //After task execution Hook,Similar to callback function
                            afterExecute(task, thrown);
                        }
                    } finally {
                        //After execution task Reset completedTasks Counter++,Unlock
                        task = null;
                        w.completedTasks++;
                        w.unlock();
                    }
                }
                completedAbruptly = false;
            } finally {
                //When the thread idle reaches the value we set, Worker Exit destroy.
                processWorkerExit(w, completedAbruptly);
            }
        }


It means that when the current task is not null or the task taken from the queue is not null, the worker thread will execute the task all the time. When there are no tasks to perform, try to recycle threads.

The most important function of runWorker is getTask(), which constantly takes tasks from the blocking queue and hands them to the thread for execution. Here's an analysis:

private Runnable getTask () {
            boolean timedOut = false; // Did the last poll() time out?

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

                //If the thread pool is in shutdown State
                //And the queue is empty, or the thread pool is in the stop perhaps terminate State
                //Number of online process pools-1,Return null,Recovery thread
                if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                    decrementWorkerCount();
                    return null;
                }

                //Identifies whether the current thread should timeout recycling when it is idle
                boolean timed;

                for (; ; ) {
                    int wc = workerCountOf(c);
                    //If allowCoreThreadTimeOut by ture
                    //Or the current number of threads is greater than the number of core thread pools,
                    //Time out recycling is required
                    timed = allowCoreThreadTimeOut || wc > corePoolSize;
                    //(1)
                    //If the number of threads is less than the maximum number of threads,
                    //And timeout recovery or no timeout is not allowed,
                    //Then jump out of the loop and continue to get the task in the blocking queue (2)
                    if (wc <= maximumPoolSize && !(timedOut && timed))
                        break;
                    //If above if If not, the current number of threads-1,Return null,Recycle this thread
                    if (compareAndDecrementWorkerCount(c))
                        return null;
                    //If above if Not established, then CAS modify ctl Fail, reread, cas Loop retry modification
                    c = ctl.get(); // Re-read ctl
                    if (runStateOf(c) != rs)
                        continue retry;
                    // else CAS failed due to workerCount change; retry inner loop
                }

                //(2)
                try {
                    //If idle recycle is allowed, the poll,
                    //otherwise take,Wait until there are desirable tasks in the queue
                    Runnable r = timed ?
                            workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                            workQueue.take();
                    //Get the task, return to the task,
                    //Otherwise, timeout. timedOut = true;Go to the next cycle,
                    //And will not be established at (1) and enter cas modify ctl In the program
                    if (r != null)
                        return r;
                    timedOut = true;
                } catch (InterruptedException retry) {
                    timedOut = false;
                }
            }
        }

Topics: PHP less