【Thread】- ThreadPoolExecutor执行过程分析

public static void main(String[] args) throws Exception{
        int corePoolSize = 5;
        int maximumPoolSize = 10;
        int blockingQueueSize = 13;
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize, //最小线程数
                maximumPoolSize, //最大线程数
                100, TimeUnit.MILLISECONDS, //超过最小线程数的线程,空闲多久则回收
                new ArrayBlockingQueue<>(blockingQueueSize, true)//放到某个队列里
        );
        //是否去掉非活动线程
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        //默认创建最小线程数的线程
        threadPoolExecutor.prestartAllCoreThreads();
        Set<Long> threadId = new HashSet<>();
        long threadsStartTime = System.currentTimeMillis();
        for (int i = 0; i < 20; i++) {
            threadPoolExecutor.execute(() -> {
                try {
                    long threadStartTime = System.currentTimeMillis();
                    Thread thread = Thread.currentThread();
                    long id = thread.getId();
                    long subTime = threadStartTime - threadsStartTime;
                    System.out.println("threadsStartTime:"+threadsStartTime+",threadStartTime:"+threadStartTime+",subTime:"+ subTime +",id:"+id);
                    Thread.sleep(3000);
                    if(threadId.contains(id)){
                        System.out.println("已存在的线程执行任务:"+id +":"+thread.getName());
                    }else{
                        threadId.add(id);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        System.in.read();
    }

测试

  • 创建20个任务,阻塞队列长度为18,线程池最小线程数为5,最大线程数为10

在这里插入图片描述
从上图可知,线程池创建了5个线程处理了5个任务,15个任务扔进了队列

  • 创建20个任务,阻塞队列长度为13,线程池最小线程数为5,最大线程数为10
    在这里插入图片描述
    从上图可知,线程池创建了7个线程处理了7个任务,13个任务扔进了队列
  • 创建20个任务,阻塞队列长度为9,线程池最小线程数为5,最大线程数为10
    在这里插入图片描述
    从上图可知,线程池创建了10个线程处理了10个任务,9个任务扔进了队列,一个任务被拒绝

源码分析

基于测试结果,应该对其执行过程有了初步的了解

execute(Runnable command)

/**
 * Executes the given task sometime in the future.  The task
 * may execute in a new thread or in an existing pooled thread.
 *
 * If the task cannot be submitted for execution, either because this
 * executor has been shutdown or because its capacity has been reached,
 * the task is handled by the current {@code RejectedExecutionHandler}.
 *
 * @param command the task to execute
 * @throws RejectedExecutionException at discretion of
 *         {@code RejectedExecutionHandler}, if the task
 *         cannot be accepted for execution
 * @throws NullPointerException if {@code command} is null
 */
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) {
        //如果线程池中线程数没有达到corePoolSize,则新增线程(worker)
        if (addWorker(command, true))
            return;
        //更新c值。
        c = ctl.get();
    }
    //线程池处于RUNNING状态,并且阻塞队列未满
    //workQueue.offer(command)是非阻塞方法,当队列满时直接返回false(例如,SynchronousQueue如果没有线程在阻塞take,则返回false)
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        //再次检查状态,如果发现不是RUNNING状态,则remove掉刚才offer的任务。
        if (! isRunning(recheck) && remove(command))
            reject(command);
        //如果有效线程数==0,添加一个线程,而不去启动它。??
        //怎么会==0?
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    //如果不是RUNNING状态,或者阻塞队列已满,则添加线程
    //如果不能添加,则reject。
    //false 表示添加的线程属于maximumPoolSize,如果线程数已经达到maximumPoolSize,则reject
    else if (!addWorker(command, false))
        reject(command);
}

阻塞队列(BlockingQueue) 的一些操作方法

* 抛出异常 特殊值 阻塞 超时
插入 add(e) offer(e) put(e) offer(e, time, unit)
移除 remove() poll() take() poll(time, unit)
检查 element() peek() 不可用 不可用

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 &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            //1. 处于 STOP, TYDING 或 TERMINATD 状态 并且 
            //2. 不是SUHTDOWN 或者 firsttask != null 或 queue不为空
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            //wc大于最大容量。
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                //没有空余的线程了。
                return false;
            //有效线程数加一,加一成功后break
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  // Re-read ctl
            //runState改变,从头执行逻辑。
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
            //else runState 没变,重新去执行加一操作。
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        //创建worker
        w = new Worker(firstTask);
        final Thread t = w.thread;
        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) {
                //添加成功,启动线程
                //启动后执行runWorker(this);
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

runWorker(Worker w)
运行worker,该线程不断的getTask()从队列中获取任务,然后 task.run();运行。只要队列中有值则不断循环。

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        //getTask()方法是个无限循环, 会从阻塞队列 workQueue中不断取出任务来执行.
        //addWorker(null, false);情况,task==null,这样就需要getTask从队列中取任务执行(自己不带任务)。直到getTask返回null
        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);
    }
}

getTask()

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.
        // STOP以上状态,或者SHUTDOWN状态下queue为空,即都没有任务要执行了。
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            //线程数减一
            decrementWorkerCount();
            //该线程退出。
            return null;
        }
        //下面都是RUNNING状态,或SHUTDOWN状态queue!=null

        int wc = workerCountOf(c);

        // Are workers subject to culling?
        //设置了allowCoreThreadTimeOut,或者线程数大于core线程数。
        //是否剔除超时的线程?
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        
        // 通过返回 null 结束线程。
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
               //线程已经准备好,正在take(),没有什么标志位?
            
            //取出runnable 返回
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

结论

线程池执行任务流程

  • 当线程数小于线程池的最小线程数时,会创建线程去执行任务
  • 当线程池的线程数大于等于线程池的最小线程数时,如果线程池处于运行状态,且阻塞队列没满时,则将任务塞进队列
  • 如果队列满时,但线程池的线程数小于最大线程数时,直接创建线程去处理任务
  • 否则拒绝任务
发布了148 篇原创文章 · 获赞 159 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_33594101/article/details/103614246