线程池浅析

基本信息介绍

1.线程池是利用一个Integer也就是32位来保存线程池的基本信息,包括线程池状态,核心线程数量。

    //当前核心线程数
	private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int COUNT_BITS = Integer.SIZE - 3;
    //最大的核心线程数量 00011111 11111111 11111111 11111111 
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // runState is stored in the high-order bits
    //运行状态 11100000 00000000 00000000 00000000
    private static final int RUNNING    = -1 << COUNT_BITS;
    //结束状态 00000000 00000000 00000000 00000000 
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    //停止    00100000 00000000 00000000 00000000 
    private static final int STOP       =  1 << COUNT_BITS;
    //       01000000 00000000 00000000 00000000 
    private static final int TIDYING    =  2 << COUNT_BITS;
    //       01100000 00000000 00000000 00000000 
    private static final int TERMINATED =  3 << COUNT_BITS;

    // Packing and unpacking ctl
	/**
	 *RUNNING  =   				11100000 00000000 00000000 00000000
	 *CAPACITY =          		00011111 11111111 11111111 11111111
	 * 一开始c(ctl)为:    		11100000 00000000 00000000 00000000
     * 增加一个核心线程之后: 		11100000 00000000 00000000 00000001
	 *CAPACITY 取反 ~CAPACITY:	11100000 00000000 00000000 00000000
	 *所以runStateOf 为:
	 *	c &  ~CAPACITY=
	 *	11100000 00000000 00000000 00000000 (c)
	 *	&
	 *	11100000 00000000 00000000 00000000 ( ~CAPACITY)
	 *	=
	 *	11100000 00000000 00000000 00000000 = RUNNING  
	 */
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    /**
     *计算当前核心线程数的数量
     * CAPACITY = 00011111 11111111 11111111 11111111
     * RUNNING  = 11100000 00000000 00000000 00000000
     * int c = ctl.get();//当前核心线程数.一开始的时候
     * ctl = ctlOf(RUNNING, 0);
     *     = RUNNING | 0
     *     = RUNNING  
     * 
     * 一开始c(ctl)为:    11100000 00000000 00000000 00000000
     * 增加一个核心线程之后: 11100000 00000000 00000000 00000001
     * 当前核心线程 workerCountOf(int c)  { return c & CAPACITY; }
     * 11100000 00000000 00000000 00000001 
     * &
     * 00011111 11111111 11111111 11111111
     * =
     * 00000000 00000000 00000000 00000001 
     * 未计算简单流程
     */
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    private static int ctlOf(int rs, int wc) { return rs | wc; }
	/**
     * Timeout in nanoseconds for idle threads waiting for work.
     * Threads use this timeout when there are more than corePoolSize
     * present or if allowCoreThreadTimeOut. Otherwise they wait
     * forever for new work.
     * 这个时间是获取task的超时时间。
     * 1.当线程池的线程数量不大于核心线程数的时候,
     * 当allowCoreThreadTimeOut=false(默认为false)那么所有线程将一直等待任务不会超时(wait forever)。
     * 当allowCoreThreadTimeOut=true的时候所有线程(包括核心线程数和超过非核心线程数的线程)都要按照超时时间(keepAliveTime)来获取任务。(也就是在keepAliveTime获取不到任务的话就回超时)
     *2.当线程池的数量大于核心线程数的时候,所有线程(核心线程和非核心线程)都将按照超时时间(keepAliveTime)来获取任务。(也就是在keepAliveTime获取不到任务的话就回超时)
     */
    private volatile long keepAliveTime;
	
	
	 /**
     * Core pool size is the minimum number of workers to keep alive
     * (and not allow to time out etc) unless allowCoreThreadTimeOut
     * is set, in which case the minimum is zero.
     * 扩展:其实核心线程和非核心线程没有本质的区别,这对于一些朋友可能会有一些误区。还有一点就是在RUNNING状态下的线程池,当没有任务可以获取的时候,最后剩下的线程的数量不一定就是corePoolSize的数量。可能的情况有:
     * 1.正好与corePoolSize相等。(当allowCoreThreadTimeOut=false,任务数量不小于corePoolSize)
     * 2.小于corePoolSize。(这种情况是当你的任务数量小于corePoolSize,eg:当你的corePoolSize为6,但是你只有3个task,那么最后线程池中剩余的线程数量就是3.)
     * 3.为0。(这种情况下是设置了allowCoreThreadTimeOut=true)
     */
    private volatile int corePoolSize;


	/**
     * If false (default), core threads stay alive even when idle.
     * If true, core threads use keepAliveTime to time out waiting
     * for work.
     * 这个参数会让核心线程也按照keepAliveTime获取任务。
     */
    private volatile boolean allowCoreThreadTimeOut;
private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {//判断线程池状态
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            /**
             *1、判断线程池当前是否为可以添加worker线程的状态,可以则继续下一步,不可以return false:
             *  A、线程池状态>shutdown,可能为stop、tidying、terminated,不能添加worker线程
			 *  B、线程池状态==shutdown
			 * 	    a.firstTask不为空,不能添加worker线程,因为shutdown状态的线程池		
			 *        不接收新任务
    		 *      b.firstTask==null,workQueue为空,不能添加worker线程,因为
    		 *	  	  firstTask为空是为了添加一个没有任务的线程再从workQueue获取task,而workQueue为  
    		 *	      空,说明添加无任务线程已经没有意义
             */
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {//判断核心线程池数量
                int wc = workerCountOf(c);
                /**
                 * 1.如果大于线程池的最大容量(2^29 - 1)。直接false
                 * 2.如果创建的是核心线程,那么如果超出核心线程数的最大值:false。
                 *   如果创建的不是核心线程数,那么如果超出最大线程数:false
                 *
                 */
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                 /**
                  *线程数增加成功:跳出最外层循环
                  */
                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;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                /**
                 *这个锁可以控制worker增加
                 */
                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) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            //如果worker从创建到启动的过程中出现了异常,那么要回滚之前的信息。
            //1.从workers中移除加入的worker。(如果成功加入的话)
            //2.当前线程的数量减一。
            //3.tryTerminate
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

2.几个状态的转换。因为在线程池中状态的转换比较多,但是我们初次阅读源码的时候会因为看不懂状态和含义而苦恼,所以我在这里简单的总结一下。

	其实线程的状态虽然有5种,但是我们可以大体上分为三种(RUNNING,Shuting Down,TERMINATED ),这也是ThreadPoolExector中toString()方法所描绘的。平时中我们关心的可能只有(RUNNING,TERMINATED ),而剩下的几个状态主要是线程池内部用到。
	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;
	
	private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

1.RUNNING:最初的状态RUNNING来自于。

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

对象创建之初就是RUNNING。
2.SHUTDOWN:来自于shutdown();方法。这个状态下线程池不会再接收先任务,但是队列中原有的任务会继续执行完。

public void shutdown() {
      final ReentrantLock mainLock = this.mainLock;
      mainLock.lock();
      try {
          checkShutdownAccess();
          advanceRunState(SHUTDOWN);
          interruptIdleWorkers();
          onShutdown(); // hook for ScheduledThreadPoolExecutor
      } finally {
          mainLock.unlock();
      }
      tryTerminate();
  }

3.STOP:该状态来自于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;
    }

4.TIDYING:来自于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
        }
    }

5.TERMINATED。当线程池不在RUNNING状态的时候,例如调用了shutdown(),shutdownNow(),线程池的最终状态就会进入TERMINATED。

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

线程池中的中断操作(tryTerminate();)只会中断从队列中获取任务的操作,而不会中断task的执行操作。

当线程池有负面增益的时候回调用tryTerminate()。那么主要都在哪些地方调用了呢?我在这里总结一下,当然也可以通过源码直接看到。
//添加线程失败
private void addWorkerFailed(Worker w){....}

//线程退出
private void processWorkerExit(Worker w, boolean completedAbruptly) {....}

//调用shutdown方法
public void shutdown() {...}

//调用shutdownNow
public List<Runnable> shutdownNow() {...}

//当线程池不是RUNNINT状态,并且新加入的任务没有被执行的时候
public boolean remove(Runnable task) {...}

/**
 *以上就是线程池源码主要用到的地方。
 *通过分析tryTerminate()源码我们可以总结出来:当线程池即将结束的时候,也就是不在是RUNNING,或者队列中没有任务的时候才会尝试终止线程池。
 *这个时候线程池中的其他线程可能依旧在获取队列中的任务,不过都在那儿阻塞呢,这个时候这些线程就释放了worker上的锁,那么tryTerminate()这个方法的机会就来了,咔嚓一下子就给这些阻塞在上面的线程池中断了,这些被中断的线程只能重新再getTask中获取任务,但这时候这个被中断的线程再次通过getTask的时候已经发现队列为空了,就直接把线程池的线程数量减一,就把null返回了,然后runWork就执行到processWorkerExit()这里面会从workers中移除当前被中断的线程,这个时候总的线程数量就少一个了,这个时候processWorkerExit还回去看一下当前是线程池状态。
 if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false);
        }
若果是STOP那就不管了,线程数就回减一。如果是SHUTDOWN或者RUNNING就会去看看当前线程池最后允许剩下多少个线程,如果最后可以剩下0个那么min就是1,如果允许最后剩下corePoolSize那么min=corePoolSize,这个时候就要去看看线程池中到底还有没有线程了,如果还有,就看看剩下的多还是min多,如果剩下的多就不管了。等线程池中的其他线程执行到processWorkerExit就又会减一个线程。等最后一个线程执行到processWorkerExit这里之后还依旧要去看一下,到底是剩下的多还是min多,因为是最后一个线程了所以剩下的线程最大也不会超过min了,因为前边已经把它减一了。

 */

推荐:https://www.cnblogs.com/trust-freedom/p/6681948.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值