线程池ThreadPoolExecutor源码分析(二)

4 篇文章 0 订阅
2 篇文章 0 订阅

简述:在上一篇博客当中介绍了java当中提供的线程池的内容,线程池介绍和常用的线程池分析(一)这篇文章主要是分析下实现线程池的源码ThreadPoolExecutor。以下内容基于JDK1.8

关于ThreadPoolExecutor的基本参数我们在上篇文章当中已经介绍过了,现在先来看下ThreadPoolExecutor的继承关系体系

我们从上往下看下,每个类或者接口主要是提供了哪些方法

Executor这个接口里面只有一个execute(Runnable command)接口

接下来ExecutorService接口

这里面的接口在原来基础上,可以看到提供了更丰富的对线程的操作,以及线程执行结果的获取

AbstractExecutorService是个抽象类,主要是对ExecutorService接口方法的一些实现。

基础属性

  private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); 
 //这个状态位是来记录workerCount和runState的值,高三位是运行状态,低29位是workerCount的值

  private static final int COUNT_BITS = Integer.SIZE - 3; // 29
  private static final int CAPACITY   = (1 << COUNT_BITS) - 1; //容量 2^29 -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; 

    // 所有的任务都中止了,workCount变为0,并且会去执行terminated方法
    private static final int TIDYING    =  2 << COUNT_BITS; 


    // 在TIDYING状态的基础上,执行完了terminated方法
    private static final int TERMINATED =  3 << COUNT_BITS; 

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

    private final ReentrantLock mainLock = new ReentrantLock(); 

 private final HashSet<Worker> workers = new HashSet<Worker>(); //存放执行的任务

 private final Condition termination = mainLock.newCondition(); //终止条件

//线程池执行过得最大线程数 
private int largestPoolSize; 

//已经完成的线程数
 private long completedTaskCount; 

//创建线程的线程工厂
private volatile ThreadFactory threadFactory; 

//拒绝策略
 private volatile RejectedExecutionHandler handler; 

//线程存活时间 
private volatile long keepAliveTime; 

//是否允许核心线程存活
private volatile boolean allowCoreThreadTimeOut; 

//核心线程数 
private volatile int corePoolSize; 

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

 

准备工作:

 

我们先来看下Worker的具体实现,Worker的内部属性

 private final class Worker extends AbstractQueuedSynchronizer
        implements Runnable
    {
 final Thread thread; //构造的是,基于当前work对象创建的线程

 Runnable firstTask; //用户提交过来的任务

 volatile long completedTasks; //完成的任务数

//tryAcquire 直接修改任务状态,从0改为1,设置AQS中的线程
 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;
        }

 Worker(Runnable firstTask) {
            setState(-1); // 将AQS当中的状态位设置为-1 ,0 表示未加锁,1 表示加锁
            this.firstTask = firstTask; //提交进来的任务
            this.thread = getThreadFactory().newThread(this); //基于当前worker创建一个线程
        }

 public void run() {
            runWorker(this);
        }

        public void lock()        { acquire(1); }
        public boolean tryLock()  { return tryAcquire(1); }
        public void unlock()      { release(1); }
        public boolean isLocked() { return isHeldExclusively(); }


}

接下来我们来看下提交线程时,都会执行哪些操作

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
       /**
        step1: 如果当前线程池当中的数量小于核心线程数,那么会尝试去创建一个新的线程,每次添加worker都会检查
               runState和workerCount,防止在不应该添加任务时增加了线程,返回false
        step2: 如果线程成功添加到队列当中去了,我们需要再次检查我们是否需要增加一个线程(可能在我们上次检查过后线程死亡了)
               或者是在线程进入这个方法时,线程shutDown了,所以我们再次检查状态
               如果线程池状态stop,需要把加入到队列中的线程回滚出来,或者也有可能是没有线程再重新创建线程去执行
        step3: 如果不能讲一个任务添加到队列中去,会尝试去创建一个新的线程
               如果创建线程失败了,可能是线程池shutdown也可能是队列满了,需要执行拒绝策略

       */
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) { //判断当前线程数是否大于核心线程数
            if (addWorker(command, true))  // 小于核心线程数,添加到核心池当中,如果添加成功,则直接返回
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) { //如果线程池状态是running,那么将任务添加到队列中
            int recheck = ctl.get(); //再次获取到线程池状态
            if (! isRunning(recheck) && remove(command)) //如果线城池不是running状态,将之前添加的任务从队列中移除
                reject(command); //执行决绝
            else if (workerCountOf(recheck) == 0) //worker数量等于0
                addWorker(null, false); //添加worker
        }
        else if (!addWorker(command, false)) //如果添加worker失败
            reject(command); //执行拒绝策略
    }

 

当我们初始化好一个线程池的时候,workerCountOf(c)返回0,假设是小于核心线程数的,我们来看下是如何处理新来的任务addWorker方法

 

 private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get(); //是一个很大的负数,初始化时 -536870912
            int rs = runStateOf(c); // 初始化的时候,-536870912

            // 当前rs的状态小于0,
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c); // 获取线程池中线程数量
                if (wc >= CAPACITY ||  如果wc大于capacity,或者wc大于核心线程数,或者大于最大线程数直接返回false
                    wc >= (core ? corePoolSize : maximumPoolSize)) 
                    return false;
                if (compareAndIncrementWorkerCount(c)) //将ctl的值加一,跳出当前for循环
                    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) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    //获取runStateOf的值,前面ctl已经增加1 ,这里获取到rs的值和上面是一样的
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||  //如果当前rs值小于0,或者 rs值和0相同并且firstTask = null
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w); //在workers集合当中添加当前worker
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;  //记录最大执行的线程数
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) { //如果添加worker成功,将线程启动
                    t.start();  //执行worker的run方法,run方法调用的runWorker方法
                    workerStarted = true; //将workerStarted的值修改为ture,并且返回
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

在addWorker方法的执行流程

1、原子更新ctl,将workerCouter增加1

2、创建一个worker,在workerSet当中添加新创建的worker

3、如果超过了largestPoolSize,就更新

4、执行runWorker方法

5、如果添加worker失败,将worker从workerSet中移除,原子更新workerCount的值

前面已经分析过runWoker方法,会获取work当中的提交过来的任务,如果不为null就执行,如果为null, 尝试从缓存队列中获取任务执行

 final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask; //获取用户提交过来的任务
        w.firstTask = null; //将worker当中firstTask清空
        w.unlock(); // 将AQS的状态位改为0,无锁状态
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock(); // worker加锁,状态设置成1
                // 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
                if ((runStateAtLeast(ctl.get(), STOP) || //当前线程状态高于stop
                     (Thread.interrupted() &&       //当前调用线程是否中断
                      runStateAtLeast(ctl.get(), STOP))) && //再次判断线程状态高于stop
                    !wt.isInterrupted())  // 执行线程是否中断
                    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++; //任务完成数量加1
                    w.unlock(); //将AQS的状态位设置为0,
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly); //最后执行线程退出的回调方法
        }
    }

 

接下来看下getTask方法

 

 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();  //如果线程池处于非运行状态,或者队列已经空了,workerCount减一,返回null
                return null;
            }

            int wc = workerCountOf(c); //获取线程池中workerCount值

            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; //判断是否需要关闭掉线程

            if ((wc > maximumPoolSize || (timed && timedOut)) //如果workerCount大于最大线程数 
                && (wc > 1 || workQueue.isEmpty())) { 
                if (compareAndDecrementWorkerCount(c)) // 将workerCount减一
                    return null;
                continue;
            }

            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : //等待指定时间
                    workQueue.take();   //直接从队列当中获取
                if (r != null)
                    return r; //如果不为null直接返回
                timedOut = true; 
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

接下来我们看下当阻塞队列当中没有任务,或者线程池shutDown之后都会调用的processWorkerExist方法

private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks; //线程池完成的任务数加等 每个worker线程执行完成的任务数
            workers.remove(w); //将执行完成的worker从workerSet当中移除
        } finally {
            mainLock.unlock();
        }

        tryTerminate(); //尝试去停止线程

        int c = ctl.get();
        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); //添加worker
        }
    }

这个方法主要是来记录当前线程池中执行完成的任务数,中止一些空闲线程

接下来看下shutDown方法

 public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess(); //查看每个worker线程的访问权限
            advanceRunState(SHUTDOWN); //将runState的状态修改为shutdown
            interruptIdleWorkers(); // 暂停所有空闲线程
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate(); //尝试中止线程池
    }

接下来看下tryTerminate的方法实现

final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())) //如果状态时shutdown,但是阻塞队列不为null直接返回
                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))) { //将runSate改为TIDING
                    try {
                        terminated();  //执行用户重写的terminated方法
                    } finally {
                        ctl.set(ctlOf(TERMINATED, 0)); //执行结束后将ctl中的runState改为TERMINATED
                        termination.signalAll(); //唤醒等待在termination上的线程
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

总结:线程池是如何进行线程的复用,当我们在使用线程池的时候,一开始线程池当中没有线程,用户提交过来任务,会创建worker线程来执行用户提交过来的任务,当线程数量达到了核心线程数之后,会把提交过来的任务放入到阻塞队列中去,这时候,之前创建的worker线程在执行完第一次提交过来的任务之后,会去阻塞队列当中获取任务,使用worker线程去执行,而不是新的线程(这里涉及到线程中调用run方法,是在当前线程中执行,调用start方法是新创建线程执行)。

以上是关于ThreadPoolExecutor的核心代码分析,如有问题欢迎指正~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值