1. Focus on execute

  • When poolSize < corePoolSize, the thread is created
  • If pollSize >= corePoolSize, it will try to put it in the queue, and if it can put it in the queue, it will return directly
  • If the queue is not put, but poolSize < maximumPoolSize, executes addIfUnderMaximumPoolSize
  • Notice that this is a for (;;) , that is to say, if executes addIfUnderMaximumPoolSize finally return runnable! = command, the next loop is entered
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        for (;;) {
            if(runState ! = RUNNING) { reject(command);return;
            }
            if (poolSize < corePoolSize && addIfUnderCorePoolSize(command))
                return;
            if (workQueue.offer(command))
                return;
            Runnable r = addIfUnderMaximumPoolSize(command);
            if (r == command)
                return;
            if (r == null) {
                reject(command);
                return;
            }
            // else retry}}Copy the code

2. Thread pools are thread pools

A thread pool is a thread pool because it can run a few threads to runnable. What makes it work is the Worker inner class.


      /** * Main run loop */
        public void run(a) {
            try {
                Runnable task = firstTask;
                firstTask = null;
                while(task ! =null|| (task = getTask()) ! =null) {
                    runTask(task);
                    task = null; // unnecessary but can help GC}}catch(InterruptedException ie) {
                // fall through
            } finally {
                workerDone(this); }}Runnable getTask(a) throws InterruptedException {
            for (;;) {
                switch(runState) {
                case RUNNING: {
                    if (poolSize <= corePoolSize)   // untimed wait if core
                        return workQueue.take();
                    
                    long timeout = keepAliveTime;
                    if (timeout <= 0) // die immediately for 0 timeout
                        return null;
                    Runnable r =  workQueue.poll(timeout, TimeUnit.NANOSECONDS);
                    if(r ! =null)
                        return r;
                    if (poolSize > corePoolSize) // timed out
                        return null;
                    // else, after timeout, pool shrank so shouldn't die, so retry
                    break;
                }
                // omit other states}}private void runTask(Runnable task) {
            final ReentrantLock runLock = this.runLock;
            runLock.lock();
            try {
                // Abort now if immediate cancel. Otherwise, we have
                // committed to run this task.
                if (runState == STOP)
                    return;

                Thread.interrupted(); // clear interrupt status on entry
                boolean ran = false;
                beforeExecute(thread, task);
                try {
                    task.run();
                    ran = true;
                    afterExecute(task, null);
                    ++completedTasks;
                } catch(RuntimeException ex) {
                    if(! ran) afterExecute(task, ex);// Else the exception occurred within
                    // afterExecute itself in which case we don't
                    // want to call it again.
                    throwex; }}finally{ runLock.unlock(); }}Copy the code
  • Worker is a Runnable. Look at its run function, which keeps fetching Runnable from the queue, and then runTask(Runnable).
  • We can use the corePoolSize number of workers to continuously run the runnable in the queue
  • KeepAliveTime is the amount of time that the idle Worker has to wait in a queue. If poolSize < corePoolSize, keep waiting. Otherwise, if the timeout occurs, the Worker’s run returns and the thread is destroyed.