Executors 剖析 线程池中的线程运行流程

在这里插入图片描述
其实Execute的运行流程还是比较简单的

小伙伴们可以看着图对配上源码 ,这样更容易理解

任务提交阶段

//任务提交阶段:(4个if条件路线)
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
	//判断工作数,如果小于coreSize,addWork,注意第二个参数core=true
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    } 
    //否则,如果线程池还在运行,offer到队列
    if (isRunning(c) && workQueue.offer(command)) {
		//再检查一下状态
        int recheck = ctl.get();
		//如果线程池已经终止,直接移除任务,不再响应
        if (!isRunning(recheck) && remove(command))
            reject(command);
		//否则,如果没有线程干活的话,创建一个空work,该work会从队列获取任务去执行
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    //队列也满,继续调addWork,但是注意,core=false,开启到maxSize的大门
	//超出max的话,addWork会返回false,进入reject
    else if (!addWorker(command, false))
        reject(command);
}

线程创建

//线程创建
private boolean addWorker(Runnable firstTask, boolean core) {
//第一步,计数判断,不符合条件打回false
    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);
//判断线程数,注意这里!
//也就说明线程池的线程数是不可能设置任意大的。
//最大29位(CAPACITY=29位二进制)
            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
        }
    }


//第二步,创建新work放入线程集合works(一个HashSet)
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//符合条件,创建新的work并包装task
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) {
//注意,只要是成功add了新的work,那么将该新work立即启动,任务得到执行
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
} return workerStarted;
}

线程创建


完整流程回顾:
        //任务获取与执行
//在worker执行runWorker()的时候,不停循环,先查看自己有没有携带Task,如果有,执行
        while(task !=null||(task =

getTask())!=null)

//如果没用,会调用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;
        }
        i
        nt wc = workerCountOf(c);
		// Are workers subject to culling?
		//判断是不是要超时处理,重点!!!决定了当前线程要不要被释放
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
		//线程数超出max,并且上次循环中poll等待超时了,那么说明该线程已终止
		//将线程队列数量原子性减
        if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }
        t
        ry {
			//重点!!!
			//如果线程可被释放,那就poll,释放的时间为:keepAliveTime
			//否则,线程是不会被释放的,take一直被阻塞在这里,知道来了新任务继续工作
            Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
            if (r != null)
                return r;
			//到这里说明可被释放的线程等待超时,已经销毁,设置该标记,下次循环将线程数减少
            timedOut = true;
        } catch(InterruptedException retry){
            timedOut = false;
        }
    }
}
<think>好的,我现在需要回答用户关于为什么不推荐使用Executors创建线程池的问题。用户已经提供了几个相关的引用内容,我需要结合这些信息来构建一个结构清晰的回答。 首先,我得回忆一下JavaExecutors类的作用。Executors提供了一些静态工厂方法,方便用户快速创建常见的线程池配置,比如newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor等。不过,根据阿里Java开发手册等最佳实践,直接使用Executors创建线程池是不推荐的。 接下来,我要分析具体原因。用户提供的引用[3]提到了corePoolSize,这可能与线程池参数配置有关。同时,用户的问题集中在不推荐的原因,可能需要从资源耗尽、可控性差、隐藏配置参数等方面展开。 首先,资源耗尽的问题。例如,newCachedThreadPool和newScheduledThreadPool可能允许无界的线程数量,导致在高负载时创建过多线程,耗尽系统资源。引用[3]中提到,当任务数超过corePoolSize时会创建新线程,这可能在某些情况下导致线程数失控。 其次,参数配置不透明。使用Executors创建的线程池隐藏了具体的参数设置,比如newFixedThreadPool内部使用LinkedBlockingQueue,其队列长度是Integer.MAX_VALUE,可能导致任务堆积,引发OOM。用户需要显式设置合理的队列大小和拒绝策略,而Executors默认的配置可能不适合生产环境。 第三,可控性和问题排查困难。直接使用Executors创建的线程池可能让开发者忽视线程池的核心参数,如核心线程数、最大线程数、存活时间、队列类型等。当出现性能问题时,难以调整和优化。引用[2]中的newSingleThreadExecutor虽然保证了顺序执行,但同样存在队列无界的问题。 然后,结合用户提供的引用内容,引用[1]和[2]提到了单线程池的顺序执行,而引用[3]解释了线程池创建线程的逻辑,这可能与corePoolSize的设置有关。需要将这些信息整合到回答中,说明为什么默认配置可能导致问题。 最后,给出替代方案,比如推荐使用ThreadPoolExecutor构造函数直接创建线程池,这样能明确所有参数,避免资源耗尽,并且自定义拒绝策略等。 在组织答案时,需要分点说明每个原因,并引用提供的资料作为支持。同时,要确保语言通顺,结构清晰,帮助用户理解问题所在以及如何正确实践。</think>在 Java 并发编程中,不推荐直接使用 `Executors` 创建线程池的主要原因与其隐藏关键配置参数、默认配置存在资源风险有关。具体原因可归纳为以下四点: --- ### 一、**默认配置导致资源耗尽风险** `Executors` 提供的工厂方法如 `newCachedThreadPool` 和 `newFixedThreadPool` 使用无界队列或无限创建线程的配置: - `newCachedThreadPool`:线程池的最大线程数为 `Integer.MAX_VALUE`,任务队列为 `SynchronousQueue`。在高并发场景下会持续创建新线程,可能导致线程数激增,耗尽 CPU 和内存资源[^3]。 - `newFixedThreadPool`:使用无界队列 `LinkedBlockingQueue`,当任务提交速度超过处理速度时,队列会无限堆积,最终导致内存溢出(OOM)[^3]。 --- ### 二、**关键参数不透明,可控性差** 通过 `Executors` 创建的线程池隐藏了底层参数设置,例如: ```java // newFixedThreadPool 的源码实现 public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); } ``` 开发者无法直接控制队列容量、拒绝策略等关键参数。实际项目中,队列容量需根据系统负载明确设定,避免任务堆积失控。 --- ### 三、**默认拒绝策略不适用生产环境** `Executors` 创建的线程池默认使用 `AbortPolicy`(直接抛出异常),但在任务队列满时,这种策略可能导致关键业务逻辑中断。生产环境通常需要自定义拒绝策略(如降级、日志记录或重试机制),但 `Executors` 未提供灵活配置方式。 --- ### 四、**单线程池的特殊风险** 即使 `newSingleThreadExecutor` 保证了任务顺序执行(如引用[1][^1]所述),其底层仍使用无界队列。若任务执行阻塞或耗时过长,队列会无限增长,最终引发内存溢出[^2]。 --- ### 替代方案:显式创建线程池 推荐直接使用 `ThreadPoolExecutor` 构造函数,明确配置核心参数: ```java // 示例:自定义线程池 int corePoolSize = Runtime.getRuntime().availableProcessors(); int maxPoolSize = corePoolSize * 2; BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000); RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy(); ExecutorService executor = new ThreadPoolExecutor( corePoolSize, maxPoolSize, 60L, TimeUnit.SECONDS, queue, handler ); ``` 这种方式可灵活控制线程数、队列容量和拒绝策略,提升系统稳定性和问题排查效率[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

O_0..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值