ThreadPoolExecutor代码总结

构造器

目录

构造器

饱和策略

核心

任务执行流程

Woker使用到AQS分析

总结


corePoolSize:核心线程数

maximumPoolSize:最大线程数

keepAliveTime:当总线程数大于核心线程数时,多余的空闲线程的最长停留时间

unit:对应上面的时间单位

workQueue:任务等待队列,超出核心线程数时,新任务会加入这个队列,常用的有ArrayBlockingQueue、LinkedBlockingQueue和SynchronousQueue(无界队列)等

handler:饱和策略,超出最大线程数和队列都无法存放时的饱和策略,可以实现RejectedExecutionHandler来自定义饱和策略,也可以使用jdk预制的常量,后面会解释

threadFactory:线程工厂,指定在创建线程时从此工厂中获取线程,ThreadFactory包含接口类方法 Thread newThread(Runnable r);一般用于指定线程名称

   public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }

饱和策略

CallerRunsPolicy:直接同步运行该任务

AbortPolicy:直接抛出RejectedExecutionException异常

DiscardPolicy:任务丢弃,不执行任何操作,也不抛异常

DiscardOldestPolicy:直接丢弃队列中一个最早加入的任务,然后再次execute提交当前任务

核心

任务执行流程

execute提交任务

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
      
        int c = ctl.get();
        //如果当前总工作线程数小于核心线程数
        if (workerCountOf(c) < corePoolSize) {
            //新建worker工作线程
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //超出核心线程数后,把任务加入队列workQueue
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            //如果线程池已停止,则执行饱和策略
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            //如果任务队列加入失败,并且addWorker也失败,则执行饱和策略
            reject(command);
    }

addWoker方法

 private boolean addWorker(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);
                //如果超过最大线程数,则返回false,不能新建Worker
                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 {
            //新建Worker工作线程
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                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 {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

Worker中线程run方法如下

关键点:一个worker一旦开始执行,就一直处理while循环,不断的从队列中获取task执行,一直到没有task执行时,while才停止循环,当前worker才有可能被销毁

final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            //注意这个地方是while循环,一个task执行完成后,会通过getTask继续获取新的任务去执行
            while (task != null || (task = getTask()) != null) {
                //worker锁定
                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
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), 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) {
                        //如果执行失败,抛出异常,当前worker线程会直接停止
                        thrown = x; throw new Error(x);
                    } finally {
                        //线程执行后钩子
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            //当没有任务处理时,处理worker的销毁
            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();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            //allowCoreThreadTimeOut如果为false(默认值),则即使处于空闲状态,核心线程也会保持活动状态。如果为true,则核心线程使用keepAliveTime超时等待
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
                //从队列中poll拉取任务,此处用到了keepAliveTime,也就是等待指定时间后,依然没有新任务,那么结合上面的runWorker,worker才会去停止
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

Woker使用到AQS分析

问题:

Worker为啥不直接使用ReentrantLock,而要自己实现AQS锁?

1、Worker不需要可重入,因为Worker没有需要重入的需求

2、可重入会带来新的问题,大概意思就是可能工作线程自己调用setCorePoolSize方法时,获取到锁之后,再Thread.interrupt()会出现自己中断自己的情况

翻译过来:这是因为可能正在等待任务的线程是通过未锁定来表示的,即tryLock为它们返回true。如果在这里使用ReentrantLock,在这种情况下会发生什么:那么可以按以下顺序进行操作:

setCorePoolSize-> interruptIdleWorkers-> tryLock()(在这里成功!)-> Thread.interrupt(此工作程序的线程)

参考:https://stackoverflow.com/questions/42189195/why-threadpoolexecutorworker-extends-abstractqueuedsynchronizer

 private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
       
        ......
        


        protected boolean isHeldExclusively() {
            return getState() != 0;
        }
        //尝试获取
        protected boolean tryAcquire(int unused) {
            //把state设置为1,表示占有锁
            if (compareAndSetState(0, 1)) {
                //设置排他线程
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        protected boolean tryRelease(int unused) {
            setExclusiveOwnerThread(null);
            //解锁,state改为0
            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) {
                }
            }
        }
}

总结

1、提交任务给ThreadPoolExecutor,当工作线程数<核心线程数时,此时会新建工作线程。当工作线程数>核心线程数时,此时会把任务交给队列。当队列中无法放入任务时,此时会执行饱和策略

2、工作线程是通过while循环的方式不断从队列中获取任务来执行的

3、Worker使用了AQS,没有使用ReentrantLock

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值