• 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并发编程之美》

  • 相关阅读:
    Effective C++ 读书笔记之Part1.Accustoming Yourself to C++
    Effective C++ 读书笔记之Part4.Design and Declarations
    Effective C++ 读书笔记之Part5.Implementations
    给程序猿三条身体保健的建议
    亮剑.NET的系列文章之.NET详解(开端)
    [转]英特尔工具使在多个处理器上实现线程化更加轻松
    [转]TrackBack Technical Specification
    Chapter 03 Writing Executable Statements 01
    Chapter 09Manipulating Data 01
    Chapter 00 Overview to PL/SQL
  • 原文地址:https://www.cnblogs.com/wqff-biubiu/p/12252975.html
Copyright © 2020-2023  润新知