jdk-ThreadPoolExecutor(三)---内部Worker和执行方法

第三篇了,其实关于多线程这边的话,我想一直分下去,每一篇都研究一点,不太想将所有的知识点都放在一起,放在一起,读起来太费力了,看起来也不舒服,分下来之后至少一目了然,一个个知识点很清晰。

今天的话就来看看它的一个内部类worker,这个worker应该算是核心了。

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable{
	//此处说明下worker中的锁是不可重入的,可以去看下它获取锁的逻辑,很清晰
        /**
         * This class will never be serialized, but we provide a
         * serialVersionUID to suppress a javac warning.
         */
        private static final long serialVersionUID = 6138294804551838833L;
        //当前worker所关联的对象,需要的时候也是直接获取即可	
        /** Thread this worker is running in.  Null if factory fails. */
        final Thread thread;
        //线程创建后的初始任务
        /** Initial task to run.  Possibly null. */
        Runnable firstTask;
        //线程完成的任务数量,注意这边是volatile类型的
        /** Per-thread task counter */
        volatile long completedTasks;

        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
        	//worker的初始化
        	//至于这边为什么会将state设置成-1,jdk这边是有注释的 
        	//inhibit interrupts until runWorker ,防止它在执行前被中断,至于中断时是怎么判断的,待会儿再看
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            //创建线程时将自身传入
            this.thread = getThreadFactory().newThread(this);
        }

        /** Delegates main run loop to outer runWorker  */
        public void run() {
        	//线程创建之后会运行该方法
            runWorker(this);
        }

        // Lock methods
        //
        // The value 0 represents the unlocked state.
        // The value 1 represents the locked state.

        protected boolean isHeldExclusively() {
        	//状态不为0说明某个线程获取到worker锁
            return getState() != 0;
        }

        protected boolean tryAcquire(int unused) {
        	//此处就能看见和ReentrantLock不一样,如果是0的话,说明其他线程没有获取到锁,此时CAS设置成1
            if (compareAndSetState(0, 1)) {
            	//将拥有者设置成当前线程
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            //如果此处是同一线程进入的话,一样返回fasle,表示同一个线程再次进入时不能获取到锁的
            return false;
        }

        protected boolean tryRelease(int unused) {
        	//释放线程操作,将状态设置成0,返回true
            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) {
                }
            }
        }
    }

final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        //运行之前设置状态为0,也就意味着这边可以执行中断了。
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
        	//如果task不为null,说明是刚刚创建出来的,热乎乎的线程,第二篇里面也分析了,这边的条件应该是能够直接创建线程的
        	//如果task为null,说明什么?说明此时没有能够创建出线程,那么此时就需要从队列中拿了,因此紧接着就是去队列获取
        	//getTask稍后分析,这边先主动忽略
            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
                //这边的判断比较复杂,不急,慢慢看,简化下来就是如下
                //( (1 || (2 && 3)) && 4)
                //1. 先看条件1,条件1就是在判断当前线程池的状态,是否是STOP及以上,是的,返回true,否返回false.此处就是判断出当线程池的状态
                //2. 看条件2,interrupted(),需要知道这个方法并不能去中断一个线程,只是返回当前中断状态并给清除当前状态设置成false
                //2.1 此时就有两种状态,假设当前线程的中断状态本就是false的话,此处返回,那么条件就变成((false || (false && 3) && 4),为什么此处1处是flase呢?因为只有
                //flase才会到 2,3的判断,||运算符具有短路效果,因此此时就会整个跳出if逻辑段了,那么此时条件1的false是什么呢?说明线程池的状态是RUNNING或者SHUTDOWN,此时
                //不应该被中断的。
                //2.2 此时返回的即使true,就意味着当前线程被中断过了,那么就需要再次判断线程池的状态是不是由于shutdownNow 造成的,因为shutdownNow 存在并发的问题,会修改
                //为STOP,如果是的话,返回true
                //此时条件状态为可能为(( true )  && 4)或者( false || (true && true) && 4),需要注意3位置处的状态,有可能在条件1处的时候还是false,但是由于并发的关系,此时
                //修改成STOP了,因此,就会进入到条件4的判断.
                //4. isInterrupted方法可以看见穿参为false,意味着直接返回线程状态, 如果线程没有被中断,也就是 4返回的是false,那么进入中断流程,如果中断了,拉倒,跳出循环
                if ( (  runStateAtLeast(ctl.get(), STOP)//1 || 
                		(Thread.interrupted() && //2
                				runStateAtLeast(ctl.get(), STOP)//3
                	    ) 
                      ) && !wt.isInterrupted() //4
                   )
                    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);
        }
    }


private Runnable getTask() {
		//这个注释不知道是谁的,不过写在这边莫名戳中我笑点。。。。。。
        boolean timedOut = false; // Did the last poll() time out?

        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
            
            //遇到分支我么都需要好好分析,这个才是去揣摩作者意图最好的地方
            //if条件要进来,rs必须比SHUTDOWN大
            //1.如果rs = SHUTDOWN状态,那么 rs != STOP ,此时去判断workQueue是否是空,如果是空,那么久要将线程数量减1,减掉的其实就是当前线程了,这样在外层当前线程就结束了
            //2.如果 rs > SHUTDOWN,那么rs起码是STOP了,此时|| 具有短路效果,不在获取队列任务,直接返回null
            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            boolean timed;      // Are workers subject to culling?

            for (;;) {
                int wc = workerCountOf(c);
                
                //来看看这个标志位的意义,首先,上一篇博客提到过allowCoreThreadTimeOut,设置为true的话,是允许线程有超时时间的
                //1.因此allowCoreThreadTimeOut 如果是true,那么timed就是true,也就意味着从队列中获取时也是需要超时的
                //2.如果allowCoreThreadTimeOut是false,这边和corePoolSize(核心线程数)作比较了,想想意义是什么?
                //如果当前线程数小于核心线程数,那么说明,此时线程池内只有核心线程数在运行,此时allowCoreThreadTimeOut为false,也就
                //意味着即使线程池内线程空闲,也不受超时
                //如果wc > corePoolSize ,就意味着此时有非核心线程在运行,还记得是什么时候出现的?上一篇将拒绝策略时试验过,超过核心线程但是没到
                //最大线程数时,并且队列已满,此时新起线程运行,在这种情况下,需要设置timed为true
                timed = allowCoreThreadTimeOut || wc > corePoolSize;  // 1
                	
                if (wc <= maximumPoolSize && ! (timedOut && timed))  // 2
                	//注意此处timedOut一开始就是false,因此在首次进入for循环时如果wc并没有超过最大线程数的话 会直接跳出,继续从下面逻辑中取出线程
                    break;   //3
                if (compareAndDecrementWorkerCount(c))
                	//如果很不幸的进入此的话,这边也是个CAS操作,即将数量减1,返回null出去,这边返回null并没有关系,外层依然是个无线循环
                    return null;  //4
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry; //这边说的很明显了,状态不一致,因此当前线程执行失败,所以重来
                // else CAS failed due to workerCount change; retry inner loop
            }

            try {
            	//正常情况下 timed都是false,不需要考虑超时,因此都是直接去workQueue中取,这边我们以LinkBlockQueue为例去分析
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();  
                if (r != null)
                    return r;
                timedOut = true;   
                //注意此处设置了timeOut为 true,也就是在从队列中并没有成功取出任务,r == null 了,这边设置了timeOut为true
                //这边注意下上面标注的1 和 2 的地方
                //如果1 处的 allowCoreThreadTimeOut一开始就是设置成true的话,那么在首次循环结束,再次循环到2时,此时timeOut和timed都是true,3处执行不到,就会
                //执行到4处返回null,因为之所以能循环到2,也就是之前一次循环没有取出任务
                //如果1处的allowCoreThreadTimeOut就是设置的false,设想一下wc如果一直没有超过核心线程数,那么break逻辑永远都会执行,直至线程池状态变成SHUTDOWN或者以上,才可能返回null出去
                //那么如果wc超过了呢?timed就是true了,那么此时wc如果处在maximumPoolSize以内,那么break也不会执行
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }
	
	//LinkBlockQueue的take方法,poll的操作差不多,只不过是多了超时时间
	public E take() throws InterruptedException {
        E x;
        int c = -1;
        final AtomicInteger count = this.count;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();
        try {
            while (count.get() == 0) {
            	//这边可以理解为生产者消费者的实现哦,当count内没有线程时,及await,等待,生产者生产线程
                notEmpty.await();
            }
            x = dequeue(); // 出对操作,具体细节不看
            c = count.getAndDecrement(); //返回当前值数量
            if (c > 1)
                notEmpty.signal();  //如果取出之后队列中依然有元素,唤醒notEmpty,继续取
        } finally {
            takeLock.unlock();
        }
        if (c == capacity) //这边之前也分析过为什么这样,因为如果c是等于capacity的话,那么此次取出之后,队列中实际上是可以继续生产的,因此唤醒生产者线程
            signalNotFull();
        return x;
    }

public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
        	//此处可以推断一下,就是判断当前调用线程是否有权限去执行SHUTDOWN操作,不是我们关注的重点
            checkShutdownAccess();
            advanceRunState(SHUTDOWN);  //将线程池状态设置成SHUTDOWN,此时也就表示不支持接收新任务了
            interruptIdleWorkers();  //中断所有空闲线程
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }
	
	private void advanceRunState(int targetState) {
        for (;;) {
        	//CAS操作
            int c = ctl.get();  //获取状态位
            //看看条件1处,如果c的状态位大于SHUTDOWN,假设为STOP吧,直接break掉,因为此时线程池状态其实已经超过SHUTDOWN了,不需要改了
            //如果条件1为 false的话,也是采用CAS将ctl处设置SHUTDOWN和数量,成功后直接break,如果失败了,一直循环
            if (runStateAtLeast(c, targetState) //1
            		||
                ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))) //2
                break;
        }
    }
	
	private void interruptIdleWorkers(false) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers) {
                Thread t = w.thread;
                if (!t.isInterrupted() && w.tryLock()) {  //此处为什么需要对w尝试去获取锁呢?因为worker在执行时,是需要获取锁的,也就意味着正在运行的线程是不能中断的
                    try {
                        t.interrupt(); //将空闲线程中断标志位设置成 true
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }
	//想想为什么此处会有这个方法????因为可能会有一种情况,线程池内的空闲线程进队列拿任务时,碰巧没有了,被之前的线程拿走了,并且此时队列任务为空了,因此会全部阻塞在take方法处.......,但是
//此时线程池的状态是SHUTDOWN,又不允许新任务进入,这可咋办???? 那么这边就提供了tryTerminate 这个方法,尝试去中断
	final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            if (workerCountOf(c) != 0) { // Eligible to terminate
                interruptIdleWorkers(ONLY_ONE);
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();
                    } finally {
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }





































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值