Java并发包中的线程池ThreadPoolExecutor

线程池主要解决两个问题:①线程池中线程是可复用的,节省了创建销毁线程的开销;②线程池提供资源限制和管理手段,如线程的个数,动态新增线程

一、ThreadPoolExecutor

 

 

 1.变量

    
    //高3位表示线程池状态,低29位表示线程个数
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    //线程个数掩码位数
    private static final int COUNT_BITS = Integer.SIZE - 3;
    //线程最大个数
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // runState is stored in the high-order bit
    //运行期:接受新任务并且处理阻塞队列里的任务
    private static final int RUNNING    = -1 << COUNT_BITS;
    //拒绝新任务但是处理阻塞队列里的任务
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    //拒绝新任务并且抛弃阻塞队列里的任务,同时会中断正在处理的任务
    private static final int STOP       =  1 << COUNT_BITS;
    //所有任务都执行完后当前线程池活动线程数为0,将要调用terminated方法
    private static final int TIDYING    =  2 << COUNT_BITS;
    //终止状态
    private static final int TERMINATED =  3 << COUNT_BITS;

    //阻塞队列
    private final BlockingQueue<Runnable> workQueue;

    /**
     * 独占锁
     */
    private final ReentrantLock mainLock = new ReentrantLock();

    /**
     * 工作线程集合,访问时需要加锁mainLock
     */
    private final HashSet<Worker> workers = new HashSet<Worker>();

    /**
     * 条件信号量
     */
    private final Condition termination = mainLock.newCondition();

    /**
     * 最大线程池大小,访问时需要加锁
     */
    private int largestPoolSize;

    /**
     * 已完成任务的计数器,仅在工作线程执行完后更新,访问时需加锁mainLock
     */
    private long completedTaskCount;

    /*
     * 所有用户控制变量设置为volatile
     */

    /**
     * 线程工厂
     */
    private volatile ThreadFactory threadFactory;

    /**
     * shutdown或者线程池饱和不能再处理任务时的拒绝处理程序
     */
    private volatile RejectedExecutionHandler handler;

    /**
     * 线程存活时间单位是纳秒,①核心线程设置allowCoreThreadTimeOut=true时核心线程空闲时的存活时间②除核心线程外的工作线程空闲时存活时间
     */
    private volatile long keepAliveTime;

    /**
     * 线程池核心线程数属性,为false时,核心线程空闲时一直保持活动状态,为true,核心线程空闲时keepAliveTime时间内保持活动状态。
     */
    private volatile boolean allowCoreThreadTimeOut;

    /**
     * 线程池核心线程数,运行时保持的最小线程数,设置allowCoreThreadTimeOut时,最小值为0
     */
    private volatile int corePoolSize;

    /**
     * 线程池最大线程数
     */
    private volatile int maximumPoolSize;

    /**
     * 默认拒绝处理任务的处理程序
     */
    private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();

    /**
     * 
     */
    private static final RuntimePermission shutdownPerm =
        new RuntimePermission("modifyThread");

    /* 执行finalizer时的Context,或为空*/
    private final AccessControlContext acc;

2.构造方法,初始化用户控制变量

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        //默认线程工厂Executors.defaultThreadFactory
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

3.常用方法

1)void execute(Runnable command):

    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        //当前线程池中线程个数小于设置的核心线程数,开启新线程运行
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //当前线程池中线程个数大于或等于设置的核心线程数,且线程池处于RUNNING状态,任务入阻塞队列
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                //重新检查线程池状态,若不处于RUNNING状态,删除任务并执行拒绝策略RejectedExecutionHandler
                reject(command);
            else if (workerCountOf(recheck) == 0)
                //线程处于RUNNING状态且线程个数为0,添加一个线程
                addWorker(null, false);
        }
        //如果队列满,则新增线程,新增失败则执行拒绝策略
        else if (!addWorker(command, false))
            reject(command);
    }

    private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        //CAS自旋实现工作线程数增加workerCount++,
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // 仅在必要的时候检查队列是否为空
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);
                //线程数达到最大
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                //CAS自旋实现workerCount++
                if (compareAndIncrementWorkerCount(c))
                    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;
        //创建线程  执行thread(worker),所以线程池中的线程执行的是worker的run方法
        Worker w = null;
        try {
            //通过Worker的构造方法,初始化Worker时会初始化new Thread(worker),即下面thread.start()中run方法时worker的run方法
            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();
                        //入workerSet,相应的线程销毁时,会出workers
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            //当前工作线程数
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    //workeradded成功即worker(thread+command)新建成功,thread.start()
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                //addWorker失败 还原状态  workCount--、works.remove(w)、还会尝试终止当前线程
                addWorkerFailed(w);
        }
        return workerStarted;
    }

通过execute方法发现

①当工作线程数小于核心线程数时,执行execute方法会使线程池新建一个Worker(新建一个线程实例+绑定当前任务command)实例,然后开始线程,new Thread(worker).start()

②当工作线程数等于大于核心线程数时,当前任务command入阻塞队列workQueue

研究线程池时怎么实现线程复用的?关键就是研究worker.run()

2).内部静态类Worker及实现线程复用的worker.run()

①Worker是一个继承AQS的一个不可重入独占锁

②从实例关系上:Worker与thread是一对一的关系,并且会保存创建thread执行的第一个任务firstTask和记录thread已经完成的任务数completedTasks

    private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        private static final long serialVersionUID = 6138294804551838833L;

        /** 工作线程 */
        final Thread thread;
        /** 需要创建线程时绑定command */
        Runnable firstTask;
        /** 当前线程完成的任务command数 */
        volatile long completedTasks;

        /**
         * 用线程工厂创建线程实例 new Thread(Worker)
         */
        Worker(Runnable firstTask) {
            setState(-1); // 在调用runWorker前禁止中断,下面的interruptIfStart方法 inhibit interrupts until runWorker
            this.firstTask = firstTask;//线程的第一个任务command
            this.thread = getThreadFactory().newThread(this);
        }

        /** 线程复用实现 Delegates main run loop to outer runWorker  */
        public void run() {
            runWorker(this);
        }

        //下面是不可重入独占锁的实现
        
        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) {
                }
            }
        }
    }

线程复用实质:new thread(worker).start-->worker.run()-->runWorker(worker)

    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); //将state设置为0,允许中断 allow interrupts
        boolean completedAbruptly = true;
        try {
            //这里就是线程复用的实质,不停从阻塞队列workerQueue中获取阻塞任务执行
            while (task != null || (task = getTask()) != null) {
                w.lock();//worker不可重入独占锁
                // 如果线程池正在停止Stopping,确保线程中断
                // 如果没有,确保线程没有被中断
                // 第二种情况需要复查处理
                // 清除中断时立即停止比赛
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    //执行任务前操作--空方法预留扩展
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        //实际的任务运行command.run()
                        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 {
            //执行清理工作,
            //将当前线程完成任务数累加到总任务数上
            //从workerSet中删除当前工作线程
            //尝试终止线程池
            //如果当前线程个数小于核心个数,创建线程
            processWorkerExit(w, completedAbruptly);
        }
    }

    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;
            }

            int wc = workerCountOf(c);

            // 线程是否会被销毁的标志 Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
            //销毁当前线程①线程数大于设定的最大线程数
            //          ②当大于核心线程小于最大线程数或allowCoreThreadTimeOut == true并且当前线程空闲超过keepAliveTime时
            //          ③wokerQueue为空
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    //CAS自旋保证线程安全workerCount--
                    return null;
                continue;
            }

            try {
                //配合上面的②,线程空闲时长超keepAliveTime时销毁
                //线程数小于核心线程数且allowCoreThreadTimeOut == false,调用take()阻塞出队
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

 

综上,不妨将其先简化成简单的模型:将线程创建销毁与workerQueue工作队列分开,

设置线程池核心线程数为2,同时来了4个任务command

①4个任务入阻塞队列

 

 ②创建线程thread1处理command1,创建线程thread2处理command2,线程数达到最大,其他任务继续阻塞

 

 ③thread2处理command2完毕,从队列中取出command3继续处理......结束;销毁线程

 

 实际的线程池ThreadPoolExecutor实际将①②进行了优化设计,

①边创建线程thread,边处理任务command,

②直到线程满后,任务command入工作队列

 ③已创建的线程从工作队列中获取command运行

3)void shutdown():不接受新任务,工作队列中的任务继续执行

    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            //权限检查
            checkShutdownAccess();
            //设置当前线程池为SHUTDOWN状态
            advanceRunState(SHUTDOWN);
            //设置中断标志
            interruptIdleWorkers();            onShutdown(); // 空方法ScheduledThreadPoolExecutor的钩子,(设计模式中的模板模式)
        } finally {
            mainLock.unlock();
        }
        //
        tryTerminate();
    }

4)List<Runnable> shutdownNow():不接受新任务,丢弃工作队列中的任务,返回值为工作队列

    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(STOP);
            //中断所有线程
            interruptWorkers();
            //获取工作队列
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

5)boolean awaitTermination(long timeout, TimeUnit unit):调用此方法后,当前线程被阻塞,入termination条件阻塞队列,直到线程池状态变为TERMINATED或者超时才返回。

    public boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException {
        long nanos = unit.toNanos(timeout);
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (;;) {
                if (runStateAtLeast(ctl.get(), TERMINATED))
                    return true;
                if (nanos <= 0)
                    return false;
                nanos = termination.awaitNanos(nanos);
            }
        } finally {
            mainLock.unlock();
        }
    }

4.总结:

1)巧妙用一个AtomicInteger原子变量记录线程池状态和线程池中的线程个数

2)线程池之间的状态转换(偷的图)

3)抽象了一个Worker类:

①继承AQS的不可重入独占锁

②与thread是一对一关系,并且记录了thread首次任务,完成任务次数

③thread.start()中运行的是worker.run()这也是实现线程获取工作队列元素实现线程复用的方法

4)线程复用的实质:线程延迟处理工作队列中的任务。

参考自《java并发编程之美》

posted on 2020-02-02 17:49  FFStayF  阅读(367)  评论(0编辑  收藏  举报