10线程池ThreadPoolExecutor专题

线程池参数

池状态和线程数量

// 使用一个Int类型32位同时表示:线程池状态、线程数量;高3位表示线程池状态,低29位表示线程数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 29位表示线程数量位数
private static final int COUNT_BITS = Integer.SIZE - 3;
// 线程池的容量最大CAPACITY= 2^29 -1 约 500万
// 此处注意:-1 之后的二进制补码表示:001 00000000000000000000000000000 ===》 000 11111111111111111111111111111
// 高3位全是0 低29位全是1,为后续位运算做准备
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

/**
* 高3位表示线程池状态,从低到高依次是:
* RUNNING  SHUTDOWN    STOP    TIDYING     TERMINATED
* 111      000         001     010         011
*
* RUNNING:运行中,能接收新的任务(用户能提交新任务),对于已经接收的任务,会继续处理,这个是线程池正常的情况
* SHUTDOWN:关闭中,不再接收新的任务,对于已经接收的任务会继续处理完毕
* STOP:停止中,不再接收新的任务,对积压在阻塞队列的任务也不再处理,对于正在运行的任务的线程,会进行中断。
* TIDYING:整理中,不再接收新的任务,所有的任务都会被终止,释放线程池中的线程池,直到线程数量为0
* TERMINATED:终止状态,不接受、不运行、线程池被关闭了。
*
*/
// runState is stored in the high-order bits
// 线程池的状态
// 原码 10000000 00000000 00000000 00000001 --> 反码 11111111 11111111 11111111 11111110
// 补码 11111111 11111111 11111111 11111111 --> 左移 11100000 00000000 00000000 00000000
// 运行中 RUNNING = 111 00000 00000000 00000000 00000000
private static final int RUNNING    = -1 << COUNT_BITS;
// 关闭 SHUTDOWN = 000 00000 00000000 00000000 00000000
private static final int SHUTDOWN   =  0 << COUNT_BITS;
// 停止 STOP = 001 00000 00000000 00000000 00000000
private static final int STOP       =  1 << COUNT_BITS;
// 整理中 TIDYING = 010 00000 00000000 00000000 00000000
private static final int TIDYING    =  2 << COUNT_BITS;
// 退出 TERMINATED = 011 00000 00000000 00000000 00000000
private static final int TERMINATED =  3 << COUNT_BITS;

因为是通过1个控制变量来同时控制状态和数量的,访问位的方法如下:

// Packing and unpacking ctl
private static int runStateOf(int c)     {
    // CAPACITY     = 000 11111111111111111111111111111
    // ~CAPACITY    = 111 00000000000000000000000000000
    // ctl & ~CAPACITY 就是取高3位,对应线程池状态
    return c & ~CAPACITY;
}
// 取低29位,对应线程数量
private static int workerCountOf(int c)  { return c & CAPACITY; }
// 更新ctl
private static int ctlOf(int rs, int wc) {
    // rs 是线程池状态,高3位
    // wd 是线程数量,低29位
    // 按位或就是ctl的值
    return rs | wc;
}

线程池的状态说明

  1. RUNNING:表示运行中,处于此状态的线程池,能接收新的任务(用户能提交新任务),对于已经接收的任务,会继续处理,这个是线程池正常的情况
  2. SHUTDOWN:不再接收新的任务,对于已经接收的任务会继续处理完毕
  3. STOP:不再接收新的任务,对积压在阻塞队列的任务也不再处理,对于正在运行的任务的线程,会进行中断。
  4. TIDYING:不再接收新的任务,所有的任务都会被终止,释放线程池中的线程池,直到线程数量为0
  5. TERMINATED:终止状态,不接受、不运行、线程池被关闭了。

其它属性

// 核心线程数
private volatile int corePoolSize;
// 最大线程池数
private volatile int maximumPoolSize;
// 创建线程的工厂
private volatile ThreadFactory threadFactory;
// 阻塞队列,用户存放任务的容器
private final BlockingQueue<Runnable> workQueue;
// 线程容器,Worker就是工作者,一个Worker内部封装了一个Thread线程
// 这里使用HashSet进行存储,表示工作者容器,线程容器
private final HashSet<Worker> workers = new HashSet<Worker>();
// 互斥锁,由于上面的HashSet不是并发安全的,所以操作的时候肯定需要上锁
private final ReentrantLock mainLock = new ReentrantLock();
// 等待条件
private final Condition termination = mainLock.newCondition();
// 当前线程数 > corePoolSize时候,这部分多出的线程在空闲多久之后会被销毁掉
private volatile long keepAliveTime;
// 是否允许核心线程超时
// 如果是false,核心线程不会被销毁
// 如果是true,核心线程在keepAliveTime时间后依然空闲,则会被销毁掉
private volatile boolean allowCoreThreadTimeOut;
// 一个标记变量,标记曾经线程池的最大大小
// 举例:corePoolSize = 5, maximumPoolSize = 10
// 线程池最大的时候有过8个线程,那么largestPoolSize = 8,只是标记一些曾经的最大值
private int largestPoolSize;
// 一个统计变量,线程池已经完成的任务数量
private long completedTaskCount;
// 线程池拒绝策略
// 当线程池饱和(阻塞队列满了,存不进新的任务;同时线程池的数量达到了maximumPoolSize无法再增加新线程)的时候提交新任务会触发此策略的执行
// 当线程池状态为SHUTDOWN,表示我要关闭了,不再接收新任务;此时向线程池提交新任务也会触发此策略的执行
private volatile RejectedExecutionHandler handler;

// 默认的拒绝策略,直接抛出异常(Abort是中止的意思)
private static final RejectedExecutionHandler defaultHandler =
    new AbortPolicy();

核心源码分析

execute()执行任务

  1. 首先计算当前线程池的线程数,如果 当前线程数 < corePoolSize (核心线程数),则会新创建线程,然后将任务交给这个新线程执行,创建成功直接返回,创建新线程失败则继续下一步
  2. 当前线程 >= corePoolSize 的时候,判断当前线程池状态是否是RUNNING,如果是则优先会尝试将任务方进入阻塞队列
  3. 当前线程数 >= corePoolSize,并且当前任务放入阻塞队列失败的时候,则会再次执行addWorker方法,尝试再去创建线程。
public void execute(Runnable command) {
    if (command == null)
    throw new NullPointerException();
/*
* Proceed in 3 steps:
*1. 如果运行的线程少于corePoolSize,则尝试用给定的命令作为第一个任务启动一个新线程。
* 对addWorker的调用会自动检查runState和workerCount,从而通过返回false来防止在不应该添加线程的情况下添加线程的错误警报。
*
* 2. 如果一个任务可以成功排队,那么我们仍然需要再次检查是否应该添加一个线程(因为自从上次检查以来已有的线程已经死亡),
* 或者在进入这个方法后池已经关闭。因此,我们重新检查状态,如果有必要,回滚排队停止,或启动一个新的线程,如果没有。
*
* 3.如果不能将任务排队,则尝试添加一个新线程。如果失败了,我们就知道自己被关闭或饱和了,所以拒绝了任务。
*
*/
// 获取线程池控制变量
int c = ctl.get();
// 1、当前线程数小于核心线程数
if (workerCountOf(c) < corePoolSize) {
    // 1.1 创建一个核心线程,并将这个任务给这个线程去处理
    if (addWorker(command, true))
        // 1.2 说明采集线程成功并任务提交成功,true
        return;
    // 此处说明创建线程失败
    c = ctl.get();
}
// 2、线程池运行中且任务可以提交到任务队列
if (isRunning(c) && workQueue.offer(command)) {
    // 2.1 二次检查,因为上次检查后线程可能消亡了,或是池关闭了
    int recheck = ctl.get();
    // 说明池关闭了,那么移除掉新增的任务
    if (! isRunning(recheck) && remove(command))
        // 2.2 移除后调用拒绝策略
        reject(command);
        // 此处说明二次检查线程池RUNNING,但是没有线程
    else if (workerCountOf(recheck) == 0)
        // 所以创建非核心线程,因为任务已经提交了,新线程会从队列中获取任务去执行
        addWorker(null, false);
}
    // 3、此处说明阻塞队列添加任务失败了,说明队列满了
    // 队列满如果最大线程数未满,创建线程来执行任务
else if (!addWorker(command, false))
    // 创建线程失败,队列满,最大线程数饱和,只能走拒绝策略
    reject(command);
}

addWorker()方法

// firstTask 第一个任务,非空则创建完成后执行这个任务
// core 是否根据核心线程限制,否则根据最大线程数限制
private boolean addWorker(Runnable firstTask, boolean core) {
    // 标志下面是无限循环
    retry:
    // 循环重试
    for (;;) {
        // 控制变量
        int c = ctl.get();
        // 线程池状态
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        // 这里返回false,不允许创建新线程的情况有
        // 1、状态非Running,也就是池关闭,且队列非空
        // 2、状态非Running,并且task非空
        // 3、状态是 STOP TIDYING TERMINATED
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        // 下面是允许创建线程
        // 无限循环,cas直到成功
        for (;;) {
            // 线程数量
            int wc = workerCountOf(c);
            // 大于最大容量;核心线程数下大于核心线程数;最大线程数限制下大于最大线程数,返回false
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;

            // 走到这里说明允许创建线程
            // cas 尝试加1
            if (compareAndIncrementWorkerCount(c))
                // cas 成功跳出循环
                break retry;
            c = ctl.get();  // Re-read ctl
            // 走到这里说明 cas 失败,重试
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }

    // 走到这里说明数量加1成功了
    // 标识Wie
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 创建新的工作者,内部包含一个线程,且task作为第一个任务
        w = new Worker(firstTask);
        // worker里面的线程
        final Thread t = w.thread;
        // 如果工作线程非空,下面的操作可能是将Worker放入HashSet容器了,加锁,释放锁、线程池状态校验之类的
        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());

                // 1、线程池状态 Running 可以继续
                // 2、状态为关闭中国,但是此次没有新任务,也可以继续
                // 往下创建新线程
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    // 将新创建的worker
                    workers.add(w);
                    int s = workers.size();
                    // 必要时候线程统计量
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    // 标识添加成功
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                // 启动work里面的内部线程
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        // 如果启动失败了,执行失败操作,肯定是将worker从HashSet容器移除,线程数量减少一个
    if (! workerStarted)
    addWorkerFailed(w);
}
    // 返回是否创建成功、启动成功标识
    return workerStarted;
}

内部Worker类

private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable
{
    // Worker内部持有的工作线程,就是依靠这个线程来不断运行线程池中的一个个task的
    final Thread thread;
    // 提交给这个Worker的首个任务
    Runnable firstTask;
    // 一个统计变量,记录着这个worker总共完成了多少个任务
    volatile long completedTasks;

    // 构造方法,创建Worker的时候给这个worker传入第一个运行的任务
    Worker(Runnable firstTask) {
        // 初始化AQS内部的state资源变量为-1
        setState(-1);
        // 保存一下首个任务
        this.firstTask = firstTask;
        // 使用线程工厂创建出来一个线程,这个线程负责运行任务
        this.thread = getThreadFactory().newThread(this);
    }

    // 内部的run方法,这个方法执行一个个任务
    public void run() {
        // runWorker方法,去运行一个个task
        runWorker(this);
    }

    // 实现AQS的互斥锁,这里是否持有互斥锁,不等于0就是持有
    protected boolean isHeldExclusively() {
        return getState() != 0;
    }

    // 实现AQS加互斥锁逻辑,就是CAS将state从0设置为1,成功就获取锁
    protected boolean tryAcquire(int unused) {
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }
    // 是新AQS释放互斥锁逻辑,就是将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(); }
}

runWorker方法

  1. 在while循环里面,不断获取任务和执行任务
  2. 每次task.run执行之前都加锁,然后执行,然后解锁,防止被中断
  3. 如果循环中获取到的task为null,那么退出循环并销毁worker
    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        // 获取第一个任务,赋值给task
        Runnable task = w.firstTask;
        // 置空方便gc
        w.firstTask = null;
        // 初始化同步器状态为0
        w.unlock(); // allow interrupts
        // 是否是突然被中断结束的标识
        boolean completedAbruptly = true;
        try {
            // 重点!首个任务直接运行,否则不断地从队列中获取任务去执行
            while (task != null || (task = getTask()) != null) {
                // 执行任务内部都先加锁,防止执行过程中被中断
                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
                // 校验一下线程池的状态
                // 如果是STOP TDIYING TERMINATED 那么需要中断当前线程
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                // 到了此处说明可以执行任务
                try {
                    // 钩子函数
                    beforeExecute(wt, task);
                    // 抛出的异常
                    Throwable thrown = null;
                    try {
                        // 调用  run 执行任务
                        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;
                    // 统计数量加1
                    w.completedTasks++;
                    // 解锁
                    w.unlock();
                }
            }
            // 走到这里 说明退出了死循环,当前worker需要被销毁
            completedAbruptly = false;
        } finally {
            // 销毁worker
            processWorkerExit(w, completedAbruptly);
        }
    }

getTask()方法分析

根据当前的配置设置,对任务执行阻塞或定时等待,如果这个worker因为以下任何原因必须退出,则返回null:

  1. 有多于maximumPoolSize工作者(由于调用了setMaximumPoolSize)。
  2. 池已停止。
  3. 池被关闭,队列为空。
  4. 该工作线程在等待任务时超时,超时的工作线程在计时等待前后都会被终止(即allowCoreThreadTimeOut || workerCount > corePoolSize),如果队列非空,则该工作线程不是池中的最后一个线程
*/
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.
        // 如果状态是 STOP TIDYING TERMINATED  说明线程池关闭了直接返回null
        // 如果状态是 SHUTDOWN ,同时阻塞队列为空,说明即将关闭,返回null
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            // 减少worker数量
            decrementWorkerCount();
            return null;
        }

        // 此处说明状态允许,计算当前线程数量
        int wc = workerCountOf(c);

        // Are workers subject to culling?
        // 很重要!表示从阻塞队列中获取任务是否超时, allowCoreThreadTimeOut 控制核心线程是否超时
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        // wc > maximumPoolSize 正常不会发生
        // 此处说明获取任务超时了
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            // 减少worker数量 返回 null
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            // 根据标志位,从阻塞队列中超时获取,或是一直阻塞等待获取
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            // 如果从队列中获取到任务,直接返回
            if (r != null)
                return r;
            // 否则就是超时了
            timedOut = true;
        } catch (InterruptedException retry) {
            // 否则就是超时了
            timedOut = false;
        }
    }
}

空闲线程被销毁processWorkerExit()

private void processWorkerExit(Worker w, boolean completedAbruptly) {
    // completedAbruptly 表示当前线程是因为中断而被销毁的,需要扣减次数
    // 正常超时被销毁为false
    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);
    } finally {
        // 释放锁
        mainLock.unlock();
    }
    // 尝试终止线程
    tryTerminate();

    int c = ctl.get();
    // 如果当前线程池状态是 RUNNING 或是 STOP
    if (runStateLessThan(c, STOP)) {
        // 1.常规的超时关闭线程
        if (!completedAbruptly) {
            // 这就是计算一下当前线程池允许的最小线程数
            // 正常情况是min=corePoolSize,但是当allowCoreThreadTimeout为true时候,允许销毁所有线程,则min=0
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            if (min == 0 && ! workQueue.isEmpty())
                // 如果队列非,说明至少要保留1个线程去执行,不能销毁所有,会调用下面的 addWorker(null, false); 加一个
                min = 1;
            if (workerCountOf(c) >= min)
                // 线程数量大于1,直接 返回即可
                return; // replacement not needed
        }
        // 2.说明completedAbruptly == true,说明可能是因为线程被中断(interrupted方法)而被销毁
        // 或是队列中还设有任务,需要补充一个新的worker
        addWorker(null, false);
    }
}

shutdown()优雅关闭线程池

核心实现在于销毁线程时,需要先获得worker内部的互斥锁,而在执行任务的过程中需要加锁,这样销毁线程操作时候不会直接中断线程,做到了优雅。

// 优雅关闭线程池
public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    // 加锁
    mainLock.lock();
    try {
        // 做一下安全检查
        checkShutdownAccess();
        // 改状态为 SHUTDOWN
        advanceRunState(SHUTDOWN);
        // 销毁线程池中的空闲线程
        interruptIdleWorkers();
        // 回调钩子
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    // 尝试终止线程池
    tryTerminate();
}

    // 销毁空闲的worker
private void interruptIdleWorkers(boolean onlyOne) {
    final ReentrantLock mainLock = this.mainLock;
    // 加锁
    mainLock.lock();
    try {
        // 遍历任务
        for (Worker w : workers) {
            Thread t = w.thread;
            // 核心是要尝试获取锁,任务执行过程是加了锁的,获取不到锁就无法中断任务
            // 优雅关闭的实现是要先获得锁
            if (!t.isInterrupted() && w.tryLock()) {
                try {
                    // 只有获取到互斥锁,才能中断线程,此处防止了任务执行过程中worker被中断
                    t.interrupt();
                } catch (SecurityException ignore) {
                } finally {
                    w.unlock();
                }
            }
            if (onlyOne)
                break;
        }
    } finally {
        mainLock.unlock();
    }
}

尝试终止线程池

final void tryTerminate() {
    // 循环重试
    for (; ; ) {
        // 控制变量
        int c = ctl.get();
        // 这里直接return的情况,也就是不能进行中止线程池的情况有:
        // 1. isRunning(c) 也就是当前线程池还是RUNNING正常运行,不能中止
        // 2. 线程池为SHUTDOWN 并且 阻塞队列非空,说明还有一些任务没有执行,需要继续执行任务,不能中止
        // 3. runStateAtLeast(c,TIDYING) 至少是TIDYING,也就是可能是TIDYING、TERMINATED这两种状态之一
        // 处于TIDYING、TERMINATED 状态说明线程池已经关闭完成了,正在中止或者已经中止,这里就不需要再次中止了
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && !workQueue.isEmpty()))
            return;
        // 当前线程数不为0,有线程要先关闭线程,返回
        if (workerCountOf(c) != 0) { // Eligible to terminate
            interruptIdleWorkers(ONLY_ONE);
            return;
        }

        // 走到这里,说明上面的检查情况都不满足
        // 也就是: 状态是SHUTDOWN或是STOP,阻塞队列为空,线程数为0
        final ReentrantLock mainLock = this.mainLock;
        // 加锁
        mainLock.lock();
        try {
            // 设置为 TIDYING 终止整理中
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    // 终止回调钩子
                    terminated();
                } finally {
                    // 设置为TERMINATED 已终止
                    ctl.set(ctlOf(TERMINATED, 0));
                    // 唤醒因为终止条件而沉睡的线程
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}

submit()方法

/**
* 提交任务返回 Future
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException       {@inheritDoc}
*/
public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    // Callable 包装成 RunnableFuture
    RunnableFuture<T> ftask = newTaskFor(task);
    // 内部就是调用execute()
    execute(ftask);
    return ftask;
}

不提倡使用Executors来构建线程池

newCachedThreadPool方法

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0,
                                  Integer.MAX_VALUE,
                                  60L,
                                  TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
  1. corePoolSize为0,maximumPoolSize为MAX_VALUE、阻塞队列是SynchronousQueue。
  2. 每来一个任务就使用或是创建一个线程去处理,下子提交非常多的任务,会创建非常多的线程。
  3. 线程数量太多,cpu竞争剧烈,可能cpu 100%;同时由于每个线程数量需要占用一定内存,默认1M,所以可能导致内存资源耗尽而OOM

newFixdThreadPool 方法

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads,
                                  nThreads,
                                  0L,
                                  TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
  1. 问题是使用了LinkedBlockingQueue无界队列,阻塞队列最大容量是Integer.MAX_VALUE,相当于容量没有限制
  2. 大量任务进入LinkedBlockingQueue队列,而其又在内存中,会造成OOM

newSingleThreadExecutor方法

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(
            1,1,0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>()));
}
  1. 问题同样是无界队列

newScheduledThreadPool

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

public ScheduledThreadPoolExecutor(int corePoolSize) {
    // 内部调用父类ThreadPoolExecutor线程的构造方法
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}
  1. DelayedWorkQueue延迟队列,无界,任务堆积会OOM
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值