ThreadPoolExecutor线程复用解析

一个线程在创建的时候会指定一个线程任务,当执行完这个线程任务之后,线程自动销毁。但是线程池可以复用线程,即一个线程执行完线程任务后不销毁,继续执行另外的线程任务。

ThreadPoolExecutor在创建线程时,会将线程封装成工作线程worker,并放入工作线程组中,然后这个worker反复从阻塞队列中拿任务去执行。

private boolean addWork(Runnable firstTask, boolean core){
    retry: // 标号 标号必须在一个循环的前面
    for(;;){
        int c = ctl.get(); // 获取线程池状态
        int rs = runStateOf(c);
    
        // Check if queue empty only if necessary
        if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
            return false;
        for(;;){
            int wc = workerCountOf(c);
            if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))
                // 1. 如果core是ture,证明需要创建的线程为核心线程,则先判断当前线程是否大于最大核心线程数目
                // 2. 如果core是false,证明需要创建的是非核心线程,则先判断当前线程数是否大于最大线程数目
                // 如果不小于则返回false
                return false;
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get(); // re-read ctl
            if (runStateOf(c) != rs)
                continue retry;
        }
    }
        

 addWork上半部分主要是判断当前线程数是否超过corePoolSize和MaximumPoolSize,超过了就返回false。

    // ThreadPoolExecutor.addWork()方法下半部分
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;

    try{
        // 1.创建一个worker对象
        w = new Worker(firstTask);
        // 2.实例化一个Thread对象
        final Thread t = w.thread;
        if (t != null){
            // 3.线程池全局锁
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try{
                // Rechek while holding lock
                // Back out on ThreadFactory failure of 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){
                // 4.启动这个线程
                t.start(); // JVM调用Worker中的run()方法,由于Worker实现了Runnable
                workerStarted = true;
            }
        }
    } finally{
        if (!workerStarted)
            addWorkerFailed(w);
    }
        return workerStarted;
}

创建worker对象,并初始化一个Thread对象,然后启动这个线程对象。

private final class Worker extends AbstractQueuedSynchronizer implements Runnalbe{
    final Thread thread;
    Runable firstTask;
    valatile long completedTasks; // 每个线程任务计数器
    
    Worker(Runnable firstTask){
        setState(-1); // 禁止中断直到执行任务
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this); // 创建了一个线程
    }

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

Worker类实现了Runnable接口,所以Worker也是一个线程任务。在构造方法中,创建了一个线程,线程的任务就是自己。故addWorker方法调用addWorker方法源码下半部分中t.start(),会触发Worker类的run方法被JVM调用。

// Worker.runWorker方法源码
final void runWorker(Worker w){
    Thread wt = Thread.currentThread(); // 获取当前的线程
    Runable task = w.firtTask;
    w.firstTask = null;
    // 1.线程启动之后,通过unlock方法释放锁
    w.unlock; // 允许打断
    boolean completeAbruptly = ture;
    try{
        // 2. Worker执行firstTask或从workQueue中获取任务,如果getTask方法不返回null,循环一直继续
        while(task != null || (task = getTask()) != null){
            // 2.1 进行加锁操作,保证thread不被其他线程中断(除非线程池被中断)
            w.lock();
            // 如果线程池停止,确保线程被打断
            // 如果没有停止,确保线程不被打断,这需要再检查去处理shutdownNow方法
            // 2.2检查线程池状态,如果线程池处于中断状态,当前线程将中断
            if ((runStateAtLesast(ctl.get(), STOP) || (Thread.interrupted() &&
                runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted())
                wt.interrupted(); // 当前线程中断
            try{
                //2.3 执行beforeExecute
                beforeExecute(wt, task);
                Throwable thrown = null;
                try{
                    // 2.4 执行任务
                    task.run();
                // 捕获执行过程中的异常
                } catch(RuntimeException x){
                    thrown = x;
                    throw x;
                } catch(Error x){
                    thrown = x;
                    throw x;
                } catch(Throwable x){
                    throw n= x;
                    throw new Error(x);
                } finally{
                    // 2.5 执行afterExecute方法
                    afterExecute(task, thrown);
                }
           } finally{
               task = null;
               w.completeTasks++;
               // 2.6 解锁操作
               w.unlock();
           }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

首先去执行创建这个worker时就有的任务,当执行完当前任务后,worker会通过getTask方法从workQueue中获取任务然后通过task.run()执行任务,从而达到复用线程的目的。

private Runnable getTask() {
        boolean timedOut = false; // 最后一个弹出是否超时

        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?
            // 1. allowCoreThreadTimeOut变量默认是false,核心线程即使空闲也不会销毁
            // 如果为true,核心线程在keepAliveTime内仍空闲就会被销毁
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            // 2. 如果当前线程总数超过了最大线程数,并且任务队列已经空了,这是需要递减worker数量
            // 如果有设置允许线程超时或者线程数量超过了核心线程数量,
            // 并且线程在规定时间内均未poll到任务且队列为空则递减worker数量
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
                // 3.如果timed为true则会调用workQueue的poll方法
                // 超时时间是keepAliveTime,如果超过这个这个时间poll返回null,while就会退出,线程执行完了
                // 如果timed为false,则会调用workQueue的take方法阻塞在当前。
                // 每个WorkQueue会实现poll方法和take方法
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

核心线程会一直卡在workQueue.take方法,被阻塞并挂起,不会占用CPU资源,直到拿到Runnable然后返回(如果allowCoreThreadTimeOut设置true,那么核心线程会去调用poll方法,因为poll会返回null,所以这时候核心线程满足超时条件会被销毁).

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值