java线程池深入三-Worker

一.目的
Worker用于执行任务。

顺便了解下线程池状态流:
running可以通过shutdown方法到shutdown状态,然后之后会变成tidying状态,最后变成terminate状态。
通过shutdownNow方法,则状态直接变成:stop,然后变成tidying状态,最后变成terminate状态。

这里需要注意shutdown,shutdownNow两个方法的区别
shutdown方法,不会接收新任务,但会等待处理完任务队列中的任务再结束线程池。
shutdownNow比较粗暴,不会接收新任务,如果有任务在执行会强制中断它,然后把任务队列中的任务返回给调用方,这里就要根据业务是否允许强制中断来分析风险点。

worker为了不消耗大量cpu,会阻塞,底层是blockingQueue的阻塞获取机制。

二.基础知识
Worker在第一次创建时,会先执行传入的task,之后会从任务队列中取。
多个worker在ThreadPoolExecutor中存储是一个hashset。

Worker数据结构:
        final Thread thread;//执行线程
        Runnable firstTask;//第一个任务
        volatile long completedTasks;//当前worker已经完成的任务数

Worker继承于AQS。

核心方法是:【runWorker(Worker w) 】
基本逻辑分为:
1.如果是创建时执行,有firstTask则执行这个任务。否则从任务队列中获取
while (task != null || (task = getTask()) != null)
getTask())用于获取任务。后面会详细说明。

2.检查当前线程池状态,如果是stop(shutdownNOW方法触发),并且线程状态中断标记未设置,则设置中断位
3.执行beforeExecute方法,默认实现为空,主要是ThreadPoolExecutor交给子类去实现一些个性化逻辑
4.执行任务run方法,这里业务任务发生异常,这个worker线程会被释放。并且会如果当前线程数已经小于核心线程数则会再创建一个worker
5.执行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(); //这里的lock很重要,因为在shutdown线程池时会中断相应worker,这里加lock可以保证任务执行的原子性,防止任务执行一半,导致业务数据的不一致。
               //如果线程已经处于stop并且线程中断位未设置,则设置线程中断位。中断位需要业务任务自己去检测使用。
                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;//这个标记用于区分是异常或者中断,还是正常因为线程要回收等情况。前者异常需要在执行后面processWorkerExit方法,减少worker线程数的逻辑。
        } finally {
            processWorkerExit(w, completedAbruptly);//出现异常,或者当前线程池被关闭都会走到这个方法
//processWorkerExit主要是用于worker退出后做资源释放及相应是否需要新增worker的逻辑。
        }
    }



processWorkerExit方法逻辑:
 
private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

//移除这个worker,之后这个对象会被垃圾回收,线程也会被回收
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks;
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }

//尝试将线程池状态设置成terminate,能够设置的条件是:当前线程池状态是shutdown并且任务队列无任务或stop状态
//如果当前可设置成terminate状态,并且还有worker线程存在,则中断它
//然后设置线程池状态为TIDYING:到达这个状态则说明当前线程数为0了,并且整个线程池已无任务。
//最后加锁执行terminate方法。这里是空方法,子类可以实现特列逻辑。
        tryTerminate();

        int c = ctl.get();

//下面的代码主要是看是否需要创建新的worker用于替换这个释放掉的worker
//两种情况会需要创建新的worker。
//1.当前被释放的worker由于异常代码
//2.当前是正常退出(由于之前线程超过核心线程数或者由于超过最大线程数,或者是检测到了shutdown信号)
//然后发现这时发现还有任务待执行,则创建一个worker

        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
//当前线程池未关闭。处于running或shutdown状态。并且是正常因为
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
//worker线程已经超过核心线程数就不需要再创建worker了
                    return; // replacement not needed
            }
            addWorker(null, false);//创建worker,底层还是会根据线程池及是否有任务等情况看是否需要创建
        }
    }

你可能感兴趣的:(java基础)