Java 线程池原理总结,结合源码

14 篇文章 1 订阅

目录

总体设计

Executor

ExecutorService

AbstractExecutorService

ThreadPoolExecutor

ThreadPoolExecutor运行流程图:

线程池生命周期管理

生命周期状态转换流程图:

shutdown():

shutdownNow():

线程池的任务执行机制

任务调度

任务的执行流程图:

execute(Runnable command):

 任务缓冲

阻塞队列图:

JDK的阻塞队列:

任务申请

任务申请getTask()流程图:

getTask():

任务拒绝

JDK提供的四种拒绝策略:

Worker线程管理

Worker线程

Worker执行任务的模型图:

线程池如何判断线程运行状态?​Worker继承AQS实现独占锁

Worker线程增加

addWorker()执行流程图:

addWorker()源码:

Worker线程回收

Worker线程执行任务

  run()源码:

阻塞队列的实现

LinkedBlockingQueue.take():

LinkedBlockingQueue. poll():


线程池(Thread Pool)是一种基于“池化”思想管理线程的工具,好处:

降低资源消耗:通过池化技术重复利用已创建的线程,降低线程创建和销毁造成的损耗。
提高响应速度:任务到达时,无需等待线程创建即可立即执行。
提高线程的可管理性:线程是稀缺资源,如果无限制创建,不仅会消耗系统资源,还会因为线程的不合理分布导致资源调度失衡,降低系统的稳定性。使用线程池可以进行统一的分配、调优和监控。
提供更多更强大的功能:线程池具备可拓展性,允许开发人员向其中增加更多的功能。比如延时定时线程池ScheduledThreadPoolExecutor,就允许任务延期执行或定期执行。

总体设计

线程池在Java中的体现是ThreadPoolExecutor类,ThreadPoolExecutor 类图如下:

Executor --> ExecutorService --> AbstractExecutorService --> ThreadPoolExecutor

Executor

public interface Executor {
    void execute(Runnable command);
}

顶层接口Executor提供了一种思想:将任务提交和任务执行进行解耦。用户无需关注如何创建线程,如何调度线程来执行任务,用户只需提供Runnable对象,将任务的运行逻辑提交到执行器(Executor)中,由Executor框架完成线程的调配和任务的执行部分。

ExecutorService

public interface ExecutorService extends Executor {
    void shutdown();

    List<Runnable> shutdownNow();

    boolean isShutdown();

    boolean isTerminated();

    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> Future<T> submit(Callable<T> task);

    <T> Future<T> submit(Runnable task, T result);

    Future<?> submit(Runnable task);

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

ExecutorService接口增加了一些能力:线程池管控的方法(比如停止线程池的运行);线程池状态判断;扩充执行任务的能力(为一个或一批异步任务生成Future的方法);

AbstractExecutorService

 AbstractExecutorService则是上层的抽象类,将执行任务的流程串联了起来,保证下层的实现只需关注一个执行任务的方法即可。

ThreadPoolExecutor

ThreadPoolExecutor将会一方面维护自身(线程池)的生命周期,另一方面同时管理线程和任务,使两者良好的结合从而执行并行任务。

ThreadPoolExecutor运行流程图:

图2 ThreadPoolExecutor运行流程

线程池在内部实际上构建了一个生产者消费者模型,将线程和任务两者解耦,并不直接关联,从而良好的缓冲任务,复用线程。线程池的运行主要分成两部分:任务管理、线程管理。

任务管理部分充当生产者的角色,当任务提交后,线程池会判断该任务后续的流转:

(1)直接申请线程执行该任务;
(2)缓冲到队列中等待线程执行;
(3)拒绝该任务。

线程管理部分是消费者,它们被统一维护在线程池内,根据任务请求进行线程的分配,当线程执行完任务后则会继续获取新的任务去执行。当线程从队列中获取到的任务为空的时候,线程就会被回收。

下面按照以下三个部分去详细讲解线程池运行机制:

线程池如何维护自身状态?
线程池如何管理任务?
线程池如何管理线程?

线程池生命周期管理

线程池运行的状态,并不是用户显式设置的,而是伴随着线程池的运行,由内部来维护。在具体实现中,线程池将 运行状态(runState) 和 工作线程数量 (workerCount) 两个关键参数的维护放在了一起,如下:

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

private static final int RUNNING    = -1 << COUNT_BITS;
private static final int COUNT_BITS = Integer.SIZE - 3;//SIZE = 32;

private static int ctlOf(int rs, int wc) { return rs | wc; } //通过状态和线程数生成ctl

ctl 这个AtomicInteger变量,是对线程池的 运行状态 和 工作线程数量 进行控制的一个字段。它同时包含两部分的信息:线程池的运行状态 (runState) 和线程池内工作线程的数量 (workerCount),高3位保存runState,低29位保存workerCount,两个变量之间互不干扰。用一个变量去存储两个值,可避免在做相关决策时,出现不一致的情况,不必为了维护两者的一致,而占用锁资源。

获取线程池运行状态 、工作线程数量的源码如下:

// 计算当前运行状态  
private static int runStateOf(int c)     { return c & ~CAPACITY; }
// 计算当前线程数量 
private static int workerCountOf(int c)  { return c & CAPACITY; }

ThreadPoolExecutor的运行状态有5种,分别为:

    private static final int RUNNING    = -1 << COUNT_BITS; //COUNT_BITS = 29
    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;

生命周期状态转换流程图:

图3 线程池生命周期

shutdown():不接收新任务,会处理已添加任务
shutdownNow():不接受新任务,不处理已添加任务,中断正在处理的任务 

shutdown():

    public void shutdown() {
        // 获取线程池的可重入锁
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 1.检查调用者的关闭权限
            checkShutdownAccess();
            // 2.推进线程池状态 --> SHUTDOWN
            advanceRunState(SHUTDOWN);
            // 3.中断空闲的工作线程,底层调用的 Thread.interrupt() 来中断线程的
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        // 尝试转换为 TERMINATED 状态
        tryTerminate();
    }

 3.interruptIdleWorkers():

    private void interruptIdleWorkers() {
        interruptIdleWorkers(false);
    }

    private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 1.迭代所有工作线程
            for (Worker w : workers) {
                Thread t = w.thread; //获取工作线程内部维护的Thread
                // 2.如果线程不是 已中断 状态 且 工作线程的不可重入锁可获取到(表示工作线程为空闲状态)
                if (!t.isInterrupted() && w.tryLock()) {
                    try {
                        // 3.中断线程
                        t.interrupt();
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }

shutdownNow():

    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        // 获取线程池的可重入锁
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 1.检查调用者的关闭权限
            checkShutdownAccess();
            // 2.推进线程池状态 --> STOP
            advanceRunState(STOP);
            // 3.中断所有工作线程,包含执行中的
            interruptWorkers();
            // 4.将任务队列排入一个新列表作为返回值
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        // 尝试转换为 TERMINATED 状态
        tryTerminate();
        return tasks;
    }

 3.interruptWorkers():

    private void interruptWorkers() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 迭代所有工作线程
            for (Worker w : workers)
                // 中断线程
                w.interruptIfStarted();
        } finally {
            mainLock.unlock();
        }
    }

    void interruptIfStarted() {
        Thread t;
        // worker的不可重入锁状态 >= 0 且 线程不为空 且 线程不是已中断状态 
        if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
            try {
                // 中断线程
                t.interrupt();
            } catch (SecurityException ignore) {
            }
        }
    }

线程池的任务执行机制

任务调度

任务调度/分配 是线程池的主要入口,当用户提交了一个任务,接下来这个任务将如何执行都是由这个阶段决定的。了解这部分就相当于了解了线程池的核心运行机制。

所有任务的调度都是由 execute() 方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定是直接申请线程执行,或是缓冲到队列中,亦或是直接拒绝该任务。其执行过程如下:

首先检测线程池运行状态,如果不是RUNNING,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
如果workerCount < corePoolSize,则创建并启动一个线程来执行新提交的任务。
如果workerCount >= corePoolSize,且线程池内的阻塞队列未满,则将任务添加到该阻塞队列中。
如果workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满,则创建一个新线程来执行新提交的任务。
如果workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。

任务的执行流程图:

图4 任务调度流程

execute(Runnable command):

    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        // 1.如果worker线程数 < corePoolSize,则新增Worker线程
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        // 2.如果线程池处于RUNNING状态 且 任务成功插入到阻塞队列中,则执行状态的double-check
        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)) //3.阻塞队列已满,尝试直接新增Worker线程(当前Worker线程 < maximumPoolSize会成功)
            // 4.当前Worker线程 >= maximumPoolSize,执行拒绝策略
            reject(command);
    }

 任务缓冲

任务缓冲模块是线程池管理任务的部分,线程池是以生产者消费者模式,通过一个阻塞队列来实现的。阻塞队列缓存任务,工作线程从阻塞队列中获取任务。

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。

阻塞队列图:

图5 阻塞队列

JDK的阻塞队列:

任务申请

任务的执行有两种可能:1.任务直接由新创建的线程执行。2.线程从阻塞队列中获取任务然后执行,执行完任务的空闲线程会再次去从队列中申请任务再去执行(线程会去任务缓存模块中不断地取任务执行)。第一种情况仅出现在core线程初始创建的时候,第二种是线程执行任务绝大多数的情况。

帮助线程从阻塞队列中获取任务,实现线程管理模块和任务管理模块之间的通信,由 getTask() 方法实现。

任务申请getTask()流程图:

图6 获取任务流程图

getTask() 方法进行了多次判断,为的是控制线程的数量,使其符合线程池的状态。如果线程池现在不应该持有那么多线程,则会返回null值。工作线程Worker会不断接收新任务去执行,而当工作线程接收不到任务的时候,即当getTask()返回null的时候,就会开始被回收。 

getTask():

    private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?
        // 一直循环(异常捕获了),直到得到返回值
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // 1.线程池运行状态判断:SHUTDOWN状态且workQueue为空 或者 STOP、TIDYING、TERMINATED状态
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                // 递减ctl的workerCount字段,即 workerCount - 1
                decrementWorkerCount();
                // 返回null
                return null;
            }

            int wc = workerCountOf(c);
            
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;// allowCoreThreadTimeOut,默认值false

            // 2.(工作线程数 > maximumPoolSize 或者 (工作线程数 > corePoolSize 且 超时了))
            //  且 (工作线程数 > 1 或者 任务队列为空)
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                // 递减ctl的workerCount字段,即 workerCount - 1
                if (compareAndDecrementWorkerCount(c))
                    // 返回null
                    return null;
                // 递减ctl的workerCount失败,重新执行
                continue;
            }

            try {
                // 3.从阻塞队列头取任务。工作线程数 > corePoolSize,则最大等待keepAliveTime纳秒时间;否则,一直等待下去,一直等到得到任务。
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    // 任务不为空,返回任务
                    return r;
                // 任务为空,标记获取任务超时了
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

任务拒绝

任务拒绝模块是线程池的保护部分。线程池有一个最大的容量,当线程池的任务缓存队列已满,并且线程池中的线程数目达到maximumPoolSize时,就需要拒绝掉该任务,采取任务拒绝策略,保护线程池。

JDK提供的四种拒绝策略:

    public static class CallerRunsPolicy implements RejectedExecutionHandler {
        public CallerRunsPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

    public static class AbortPolicy implements RejectedExecutionHandler {
        public AbortPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                " rejected from " +
                e.toString());
        }
    }

    public static class DiscardPolicy implements RejectedExecutionHandler {
        public DiscardPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        public DiscardOldestPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }

Worker线程管理

Worker线程

线程池为了方便掌握线程的状态并维护线程的生命周期,设计了线程池内的工作线程Worker。

Worker部分源码:

private final class Worker extends AbstractQueuedSynchronizer implements Runnable{
    final Thread thread;//Worker持有的线程
    Runnable firstTask;//初始化的任务,core线程创建时需要执行的任务

    // 构造方法
    Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);//ThreadFactory创建线程
    }
}

Worker:工作线程,实现了Runnable接口,并持有一个线程thread,一个初始化的任务firstTask。thread是在Worker构造方法中通过ThreadFactory创建出来的,用来执行任务的线程;firstTask保存了传入的第一个任务,如果这个值是非null的,那么线程就会在创建后立即执行这个任务,对应核心线程创建时的情况;如果这个值是null,那么就会创建一个线程去取任务列表(workQueue)中的任务执行,对应非核心线程的创建。

Worker执行任务的模型图:

图7 Worker执行任务

线程池如何判断线程运行状态?​Worker继承AQS实现独占锁

线程池要管理线程的生命周期,在线程长时间不运行的时候进行回收。线程池使用一张Hash表去持有线程的引用,这样可以通过添加引用、移除引用这样的操作来控制线程的生命周期。这个时候重要的就是如何判断线程是否在运行?线程池内的​Worker是通过继承AQS,通过AQS实现独占锁,进而判断线程是否空闲。没有使用可重入锁ReentrantLock,而是使用AQS,为的就是用不可重入的特性去反应线程现在的执行状态。

线程池在执行shutdown方法或tryTerminate方法时会调用interruptIdleWorkers方法来中断空闲的线程,interruptIdleWorkers方法会使用 tryLock() 尝试获取可重入锁,来判断线程池中的线程是否是空闲状态;如果线程是空闲状态则可以安全回收。

图8 线程池回收过程

Worker线程增加

addWorker() 方法用于增加线程,并使它运行,返回是否成功。addWorker方法有两个参数:firstTask、core。firstTask参数用于指定新增的线程执行的第一个任务,该参数可为空;core参数表示是否为core线程,为true在新增线程前会判断当前活动线程数是否少于corePoolSize,为false在新增线程前会判断当前活动线程数是否少于maximumPoolSize。

addWorker()执行流程图:

图9 申请线程执行流程图

addWorker()源码:

    private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (; ; ) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // 1.线程池状态的有效性判断
            if (rs >= SHUTDOWN &&
                !(rs == SHUTDOWN &&
                    firstTask == null &&
                    !workQueue.isEmpty())) {
                return false;
            }

            // 2.线程池当前工作线程数量的有效性判断
            for (; ; ) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize)) {
                    return false;
                }
                // 3.尝试增加ctl的工作线程数,即 workerCount + 1
                if (compareAndIncrementWorkerCount(c)) {
                    break retry;
                }
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs) {
                    continue retry;
                }
            }
        }

        // 3.1 工作线程数增加成功
        boolean workerStarted = false; //Worker线程开启结果
        boolean workerAdded = false;
        Worker w = null;
        try {
            // 4.创建Worker线程
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    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();
                }
                // 5.启动Worker线程内维护的Thread
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (!workerStarted) {
                addWorkerFailed(w);
            }
        }
        return workerStarted;
    }

Worker线程回收

线程池中线程的销毁依赖JVM GC的自动回收,线程池做的工作是根据当前线程池的状态维护一定数量的线程引用,防止这部分线程被JVM回收,当线程池决定哪些线程需要回收时,只需要将其引用消除即可。Worker被创建出来后,就会不断地进行轮询,然后获取任务去执行,核心线程可以无限等待获取任务,非核心线程要限时获取任务。当Worker获取到的任务为空时,循环会结束,Worker会主动消除自身在线程池内的引用。 

try {
  while (task != null || (task = getTask()) != null) {
    //执行任务
  }
} finally {
  processWorkerExit(w, completedAbruptly);//获取不到任务时,主动回收自己
}

线程回收的工作是在processWorkerExit方法完成的:

图10 线程销毁流程

事实上,在这个方法中,将线程引用移出线程池就已经结束了线程销毁的部分。但由于引起线程销毁的可能性有很多,线程池还要判断是什么引发了这次销毁,是否要改变线程池的现阶段状态,是否要根据新状态,重新分配线程。

Worker线程执行任务

在Worker类中的run方法调用了runWorker方法来执行任务,runWorker方法的执行过程如下:

1.while循环不断地通过getTask()方法获取任务。

2.getTask()方法从阻塞队列中取任务。

3.如果线程池正在停止,那么要保证当前线程是中断状态,否则要保证当前线程不是中断状态。

4.执行任务。

5.如果getTask结果为null则跳出循环,执行processWorkerExit()方法,销毁线程。

执行流程图:

图11 执行任务流程

  run()源码:

private final class Worker extends AbstractQueuedSynchronizer implements Runnable{
    // 将主运行委托给外部的runWorker
    public void run() {
        runWorker(this);
    }
}
    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            // 1.while循环 firstTask不为空 或 getTask()方法返回不为空
            while (task != null || (task = getTask()) != null) {
                // 获取Worker的独占锁
                w.lock();
                // 2.如果线程池正在停止,那么要保证当前线程是中断状态;否则,要保证当前线程不是中断状态
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);//protected void beforeExecute(Thread t, Runnable r) { }
                    Throwable thrown = null;
                    try {
                        // 3.任务Runnable执行
                        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);//protected void afterExecute(Runnable r, Throwable t) { }
                    }
                } finally {
                    // task置空
                    task = null;
                    // Worker完成的任务++
                    w.completedTasks++;
                    // 释放Worker的独占锁
                    w.unlock();
                }
                // 回到步骤1
            }
            completedAbruptly = false;
        } finally {
            // 4.getTask()方法返回的任务为空,执行worker线程的退出,即线程的回收
            processWorkerExit(w, completedAbruptly);
        }
    }
    // 执行Worker的退出
    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 {
            // 1.worker完成的任务数加入到线程池完成的任务数中
            completedTaskCount += w.completedTasks;
            // 2.线程池中维护的worker集合移除当前worker。
            //   当前worker没有了引用指向,可被GC回收,自然worker内维护的Thread也可以被GC回收掉了,线程池就是这样完成线程的回收。
            workers.remove(w);//private final HashSet<Worker> workers = new HashSet<Worker>();
        } 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);
        }
    }

阻塞队列的实现

从阻塞队列中取数据使用的 BlockingQueue api:workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)、workQueue.take(),JDK中最常用的阻塞队列实现类为ArrayBlockingQueue、LinkedBlockingQueue, 所以看一下LinkedBlockingQueue的具体实现。

LinkedBlockingQueue.take():

    public E take() throws InterruptedException {
        E x;
        int c = -1;
        final AtomicInteger count = this.count;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();
        try {
            while (count.get() == 0) {
                // 线程await(),进入等待状态
                notEmpty.await();
            }
            x = dequeue();
            c = count.getAndDecrement();
            if (c > 1)
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
    }
    /** Current number of elements */
    private final AtomicInteger count = new AtomicInteger();

    /** Wait queue for waiting takes */
    private final Condition notEmpty = takeLock.newCondition();

    private E dequeue() {
        Node<E> h = head;
        Node<E> first = h.next;
        h.next = h; // help GC
        head = first;
        E x = first.item;
        first.item = null;
        return x;
    }

LinkedBlockingQueue. poll():

    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        E x = null;
        int c = -1;
        long nanos = unit.toNanos(timeout);
        final AtomicInteger count = this.count;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();
        try {
            while (count.get() == 0) {
                if (nanos <= 0)
                    return null;
                // 线程限时等待
                nanos = notEmpty.awaitNanos(nanos);
            }
            x = dequeue();
            c = count.getAndDecrement();
            if (c > 1)
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
    }

参考:Java线程池实现原理及其在美团业务中的实践 - 美团技术团队

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值