Java线程池核心方法源码解析(附带流程图), 字字注释,一起交流

线程池核心方法源码 (附带流程图)

公众号搜索: 意姆斯Talk, 即可领取大量学习资料及实战经验
在这里插入图片描述

温馨提醒: 若图片模糊看不清, 右键图片, 点击在新标签中打开图片

前戏链接(主要是线程池中的概念, 概念决定一切)

https://blog.csdn.net/qq_37805943/article/details/114748473

1.execute(Runnable command)

command:待执行的参数

1.1源码

public void execute(Runnable command) {
		//1.判断当前任务是否为空, 若为空, 则抛出空指针异常
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         * one.  如果运行的线程少于corePoolSize,请尝试以给定的命令作为第一个线程开始一个新线程
		 *    任务。调用addWorker原子地检查运行状态和workerCount,因此可以防止错误警报
		 *    如果不应该,则会添加线程,返回false
         *
         * two. 如果任务可以成功排队,那么我们仍然需要仔细检查是否应该添加线程,(因为自从上次检查以来已有的已经死了)或者自进入此方法后,池已关闭。
         *    所以我们重新检查状态,必要时回滚排队已停止,如果没有线程,则启动新线程
         *
         * three. 如果无法将任务排队,则尝试加新的线程。如果失败了,我们就知道我们已经关闭或者饱和了
         * 所以拒绝这个任务。
         */
        //2.获取到当前线程数
        int c = ctl.get();
        //2.1若当前线程数小于核心线程数, 调用addWorker()方法添加任务, 若添加成功,直接返回
        if (workerCountOf(c) < corePoolSize) {
        	//command:当前入参, ture:核心线程数, false:最大线程数
            if (addWorker(command, true))
                return;
            //2.2添加失败, 获取当前线程数, 走阻塞队列
            c = ctl.get();
        }
        //3.若处于Running状态, 同时将当前任务添加队列成功
        if (isRunning(c) && workQueue.offer(command)) {
        	//3.1二次校验
            int recheck = ctl.get();
            //3.2若处于非Running状态&&从消息队列中成功移除当前任务
            if (! isRunning(recheck) && remove(command))
            	//调用拒绝策略方法
                reject(command);
            //3.3若当前线程数等于0
            else if (workerCountOf(recheck) == 0)
            	//3.4添加一个null任务,这个线程将去获取已经加入任务队列的本次任务并执行
                addWorker(null, false);
        }
        //4.尝试扩容maxPoolSize后再次addWorker,失败则拒绝任务
        else if (!addWorker(command, false))
            reject(command);
    }

1.2流程图

在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/202103301758513.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3ODA1OTQz,size_16,color_FFFFFF,t_70#pic_center

2.addWorker(Runnable firstTask, boolean core)

Runnable firstTask:首先执行的任务(可以为null)
boolean core: true表示核心线程数, false表示最大线程数

2.1源码

 private boolean addWorker(Runnable firstTask, boolean core) {
 		//retry用法:用于两层for循环, 跳转到第一个for循环下
 		//两个for循环的目的就是为了通过CAS算法将核心线程数量+1, 跳出整个循环
        retry:
        for (;;) {
        	//1.获取当前线程数
            int c = ctl.get();
            //2.获取当前线程池的状态
            int rs = runStateOf(c);

            /*
			*3.仅在必要时检查队列是否为空,
			*条件1: 当线程池状态>=shutdown(意思就是非running状态)
			*条件2: 不满足(线程池状态为shutdown, 同时firstTask为空,并且队列不为空)
			*两者都满足时, 返回false, 结束当前方法, 说明添加任务失败
			*/
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;
            for (;;) {
            	/*
				*4.wc:获取当前线程数
				* 条件1:当wc大于最大上限容量
				* 条件2:wc大于等于核心线程数或最大线程数
				* 返回false, 添加失败,东西太多了还加个锤子!
				*/
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                //5.若成功通过CAS算法+1, 则跳出整个循环
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                //6.再次获取当前线程数
                c = ctl.get();  // Re-read ctl
                //7.如果当前状态不等于running状态,则结束本次循环,继续for循环下去
                if (runStateOf(c) != rs)
                    continue retry;
            }
        }
		//7.开始和结束默认是false(小case:不赋值boolean默认就是false)
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            //7.1其中运行的线程
            final Thread t = w.thread;
            if (t != null) {
            	//7.2 其实就是加锁 ReentrantLock mainLock = new ReentrantLock();
                final ReentrantLock mainLock = this.mainLock;
                //7.3 开启锁(俗称:保安模式)
                mainLock.lock();
                try {
                    //7.3.1获取到当前线程数, 同时获取线程池的状态
                    int rs = runStateOf(ctl.get());
					/*
					*条件1: 若当前rs线程状态是running状态
					*条件2: 若当前线程状态是shutdown状态,并且首先执行的firstTask为空
					*两者有一个为真, 则if(true).走if判断
					*/
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        //7.3.1.1若当前线程存在(已经启动了),则抛出非法线程状态异常
                        if (t.isAlive()) 
                            throw new IllegalThreadStateException();
                        //7.3.1.2加入线程池
                        workers.add(w);
                        int s = workers.size();
                        //7.3.1.2若线程池中的数量大于上一次的最大线程数,则赋值,仅在mainLock中访问 
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                	//7.3.2释放锁
                    mainLock.unlock();
                }
                //7.3.3若加入线程池成功,则启动线程--->这就是为什么上面抛非法线程状态异常
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
        	//7.4 若线程启动失败, workerStarted=false,则调用addWorkerFailed()方法
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

2.2流程图

在这里插入图片描述

3.Worker(上述2中定义的Worker类)

在这里插入图片描述
Worker这个工作线程,实现了Runnable接口,并持有一个线程thread,一个初始化的任务firstTask。thread是在调用构造方法时通过ThreadFactory来创建的线程,可以用来执行任务;firstTask用它来保存传入的第一个任务,这个任务可以有也可以为null。如果这个值是非空的,那么线程就会在启动初期立即执行这个任务,也就对应核心线程创建时的情况;如果这个值是null,那么就需要创建一个线程去执行任务列表(workQueue)中的任务,也就是非核心线程的创建。

Worker类主要维护正在运行任务的线程的中断控制状态,以及其他次要的记录。这个类适时地继承了AbstractQueuedSynchronizer类,以简化获取和释放锁(该锁作用于每个任务执行代码)的过程。这样可以防止去中断正在运行中的任务,只会中断在等待从任务队列中获取任务的线程。

3.1源码

private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable
{
    /**
     * 此类永远不会序列化, 但是我们提供了serialVersionUID来禁止Javac警告。
     */
    private static final long serialVersionUID = 6138294804551838833L;
 
    /** 此工作线程正在运行的线程。如果工厂失败,则为null. */
    final Thread thread; 
     
    /** 最开始的任务, 可以为空. */
    Runnable firstTask;
     
    /** 线程任务计数器 */
    volatile long completedTasks;
 
    /**
     * 使用给定的第一个任务和ThreadFactory中的线程创建。 
     * firstTask: 第一个任务(如果没有则为null)
     */
    // 通过构造函数初始化,
    Worker(Runnable firstTask) {
        //设置AQS的同步状态:,锁状态,-1为初始值,0为unlock状态,1为lock状态
        setState(-1); // inhibit interrupts until runWorker  在调用runWorker前,禁止中断
       
        this.firstTask = firstTask;
        // 线程工厂创建一个线程
        this.thread = getThreadFactory().newThread(this); 
    }
 
    /* 
     *将主运行循环委托给外部runWorker()
	*/
    public void run() {
        //调用了runWorker方法来执行任务, 主要是调用runWorker里面的getTask()方法
        runWorker(this); //runWorker()是ThreadPoolExecutor的方法
    }
 	/*
	 * state: 锁状态,-1为初始值,0为unlock状态,1为lock状态
	 */
    protected boolean isHeldExclusively() {
        return getState() != 0;
    }
 
    /**
     * tryAcquire:英文翻译尝试获取, 尝试获取锁的方法
     * 重写AQS的tryAcquire(),AQS本来就是让子类来实现的
     */
    protected boolean tryAcquire(int unused) {
        // 判断原值为0,且重置为1,所以state为-1时,锁无法获取。
        // 每次都是0->1,保证了锁的不可重入性
        if (compareAndSetState(0, 1)) {
            // 设置exclusiveOwnerThread=当前线程
            setExclusiveOwnerThread(Thread.currentThread()); 
            return true;
        }
        return false;
    }
 
    /**
     * 尝试释放锁
     * 不是state-1,而是置为0
     */
    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(); }
 
    /**
     * 中断(如果运行)
     * shutdownNow时会循环对worker线程执行
     * 且不需要获取worker锁,即使在worker运行时也可以中断
     */
    void interruptIfStarted() {
        Thread t;
        //如果state>=0、t!=null、且t没有被中断
        //new Worker()时state==-1,说明不能中断
        if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
            try {
                t.interrupt();
            } catch (SecurityException ignore) {
            }
        }
    }
}

3.2Worker类的执行模型

在这里插入图片描述

3.3特点

Worker是通过继承AQS,使用AQS来实现独占锁这个功能。没有使用可重入锁ReentrantLock,而是使用AQS,为的就是实现不可重入的特性去反应线程现在的执行状态。

lock方法一旦获取了独占锁,表示当前线程正在执行任务中。

如果正在执行任务,则不应该中断线程。

如果该线程现在不是独占锁的状态,也就是空闲的状态,说明它没有在处理任务,这时可以对该线程进行中断。

线程池在执行shutdown方法或tryTerminate方法时会调用interruptIdleWorkers方法来中断空闲的线程,interruptIdleWorkers方法会使用tryLock方法来判断线程池中的线程是否是空闲状态;如果线程是空闲状态则可以安全回收。
在这里插入图片描述

4.runWorker(Worker worker)核心源码

worker: 封装的Worker,携带了工作线程的诸多要素,包括Runnable(待处理任务)、lock(锁)、completedTasks(记录线程池已完成任务数)

4.1源码

    final void runWorker(Worker w) {
    	//1.获取当前的线程
        Thread wt = Thread.currentThread();
  		//2.获取worker中封装的参数
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); 
        //3.线程退出的原因,true是任务导致,false是线程正常退出
        boolean completedAbruptly = true;
        try {
        	// 当前任务和从任务队列中获取的任务都为空,方停止循环, 详情看4.1.1中的getTask()源码解析
            while (task != null || (task = getTask()) != null) {
                w.lock();
                /**
             	* 条件1:线程池状态>=STOP,即STOP或TERMINATED
             	* 条件2:若线程已经被中断,再次检查线程池状态是否>=STOP
             	* 条件3: wt未中断时
             	* 条件1与条件2任意满意一个,并且wt不是中断状态,则中断wt,否则进入下一步
             */
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    //3.1执行前
                    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 {
                    	//3.2执行后
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    //3.3worker中的参数(线程任务计数器)completedTasks+1
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            //4.处理worker的退出
            processWorkerExit(w, completedAbruptly);
        }
    }

4.1.1getTask()源码

作用: 在任务队列(workQueue)中获取 task(Runnable)。

简化流程:

  1. while循环不断地通过getTask()方法获取任务。
  2. getTask()方法从阻塞队列中取任务。
  3. 如果线程池正在停止,那么要保证当前线程是中断状态,否则要保证当前线程不是中断状态。
  4. 执行任务。
  5. 如果getTask结果为null则跳出循环,执行processWorkerExit()方法,销毁线程。
    在这里插入图片描述
    判断里可参考如图
   private Runnable getTask() {
   		//1.设置超时变量默认为false
        boolean timedOut = false; // Did the last poll() time out?
		//2.进入循环
        for (;;) {
        	//2.1获取当前线程数和线程池的状态
            int c = ctl.get();
            int rs = runStateOf(c);

            /*
            *条件1:当前状态处于非running状态
            *条件2:线程池STOP、TIDYING、TERMINATED状态或workQueue为空
            *两者都满足时, 进入if判断
			*/
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            	//2.1线程池不必再获取任务了,当前工作线程数量-1并返回null
                decrementWorkerCount();
                return null;
            }
			//获取当前线程数量
            int wc = workerCountOf(c);

            	/*条件1:allowCore:如果为false,为处于空闲状态,核心线程也保持活动状态。 
                 *				 如果为true,则核心线程使用keepAliveTime来超时等待工作。
                 *条件2:若当前线程数量大于核心线程数,则为ture,反之为false
                 *两者满足其一,则timed=true
                 *timed:阻塞时间是否限制, ture受限,false不受限
            	 */
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
				
        		/* 条件1:工作线程数大于maximumPoolSize,或(timed为true,同时timeOut是否超时)
        		 * 条件2:wc > 1或任务队列为空(||或的意义:一true全true)
        		 *两者满足其一:则通过CAS使工作线程量减1,若成功减1,返回null
        		 */
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
			//执行到这里,说明已经经过前面重重校验,开始真正获取task了
            try {
            	// 如果工作线程阻塞时间受限,则使用poll(),否则使用take()
            	// poll()设定阻塞时间,而take()无时间限制,直到拿到结果为止
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                //r不为空,则返回该Runnable
                if (r != null)
                    return r;
                 //若runnable为null,则将超时时间设置为true,
                timedOut = true;
            } catch (InterruptedException retry) {
            	//响应中断,进入下一次循环前将最近获取任务超时状态置为false
                timedOut = false;
            }
        }
    }

4.1.2流程图

在这里插入图片描述

5.processWorkerExit(Worker w, boolean completedAbruptly)

Worker w: 要结束的工作线程。
boolean completedAbruptly : 是否突然完成(异常导致),如果工作线程因为用户异常死亡,则completedAbruptly参数为 true。

    private void processWorkerExit(Worker w, boolean completedAbruptly) {
    	//1.若工作线程因为出问题抛异常, 则为true,通过CAS算法使工作线程数-1
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();
		//2.其实就是加锁 ReentrantLock mainLock = new ReentrantLock(), 开启锁
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
        	/* 2.1
        	*     completedTaskCount =completedTaskCount + w.completedTasks;
        	*     completedTaskCount 计数器完成的任务, 只有在mainLock下才能用
        	*     将该worker已完成的任务数追加到线程池已完成的任务数
        	*/
            completedTaskCount += w.completedTasks;
            //HashSet<Worker> workers中移除要结束的工作线程
            workers.remove(w);
        } finally {
        	//2.2解锁
            mainLock.unlock();
        }
		//3 根据线程池状态进行判断是否结束线程池, 这个方法就是用来尝试终止线程池的
        tryTerminate();
		//4获取当前线程数
        int c = ctl.get();
        /**
     	* 5.是否需要增加工作线程
     	* 线程池状态是running 或 shutdown
     	* 如果当前线程是突然终止的,addWorker()
     	* 如果当前线程不是突然终止的,但当前线程数量 < 要维护的线程数量,addWorker()
     	* 故如果调用线程池shutdown(),直到workQueue为空前,线程池都会维持corePoolSize个线程,然后再逐渐销毁这corePoolSize个线程
     	*/
        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);
        }
    }

6.参考资料

[1]JDK 1.8 源码

[2] 维基百科-线程池

[3] 更好的使用Java线程池

[5] 深入理解Java线程池:ThreadPoolExecutor

[6]观看博主对线程池的看法有感: 云深i不知处

7.作者: 往下爬的小刘

end!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值