线程池的执行流程

这篇具有很好参考价值的文章主要介绍了线程池的执行流程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

线程池的执行流程

如果所示,就是线程池的执行过程,可以分为三个主要步骤:

1.提交任务后会首先进行当前工作线程数与核心线程数的比较,如果当前工作线程数小于核心线程数,则直接调用 addWorker() 方法创建一个核心线程去执行任务;

2.如果工作线程数大于核心线程数,即线程池核心线程数已满,则新任务会被添加到阻塞队列中等待执行,当然,添加队列之前也会进行队列是否为空的判断;

3.如果线程池里面存活的线程数已经等于核心线程数了,且阻塞队列已经满了,再会去判断当前线程数是否已经达到最大线程数 maximumPoolSize,如果没有达到,则会调用 addWorker() 方法创建一个非核心线程去执行任务;

4.如果当前线程的数量已经达到了最大线程数时,当有新的任务提交过来时,会执行拒绝策略

总结来说就是优先核心线程、阻塞队列次之,最后非核心线程

java.util.concurrent.ThreadPoolExecutor#execute 的源码为:

 public void execute(Runnable command) {
     if (command == null)
         throw new NullPointerException();
     /*
      * Proceed in 3 steps:
      *
      * 1. If fewer than corePoolSize threads are running, try to
      * start a new thread with the given command as its first
      * task.  The call to addWorker atomically checks runState and
      * workerCount, and so prevents false alarms that would add
      * threads when it shouldn't, by returning false.
      *
      * 2. If a task can be successfully queued, then we still need
      * to double-check whether we should have added a thread
      * (because existing ones died since last checking) or that
      * the pool shut down since entry into this method. So we
      * recheck state and if necessary roll back the enqueuing if
      * stopped, or start a new thread if there are none.
      *
      * 3. If we cannot queue task, then we try to add a new
      * thread.  If it fails, we know we are shut down or saturated
      * and so reject the task.
      */
     int c = ctl.get();
     if (workerCountOf(c) < corePoolSize) {
         if (addWorker(command, true))
             return;
         c = ctl.get();
     }
     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))
         reject(command);
 }

可以看到,源码中的注释部分也说明了整个 excute() 方法的执行过程可分为三个步骤。

源码中变量 ctl 是一个原子类,主要作用是用来保存线程数量和线程池的状态。这里采用高 3 位来保存运行状态,低 29 位来保存线程数量。

在这几个步骤中,最重要的当属 addWorker() 方法了。

private boolean addWorker(Runnable firstTask, boolean core);

第一个参数表示要执行的任务,如果为 null,则从阻塞队列中拉取任务;

第二个参数表示是否是核心线程,用来控制 addWorker() 的流程。

addWorker() 方法的实现主流程为:

线程池的执行流程

源码为:

private boolean addWorker(Runnable firstTas
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        // Check if queue empty only if nec
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;
        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize 
                return false;
            if (compareAndIncrementWorkerCo
                break retry;
            c = ctl.get();  // Re-read ctl
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to worke
        }
    }
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = 
            mainLock.lock();
            try {
                // Recheck while holding lo
                // Back out on ThreadFactor
                // shut down before lock ac
                int rs = runStateOf(ctl.get
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firs
                    if (t.isAlive()) // pre
                        throw new IllegalTh
                    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;
}

addWorker() 执行过程中会反复使用 runStateOf() 和 workerCountOf() 来获取线程池的状态和工作线程的数量。

本文参考自:三分钟弄懂线程池执行过程 - 掘金文章来源地址https://www.toymoban.com/news/detail-406725.html

到了这里,关于线程池的执行流程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 《Effective Java》如果说我需要一本Java编程的书,那就是它了

    《Effective Java》是Java编程领域的一本经典之作,由Joshua Bloch撰写,旨在帮助Java程序员提高编码技巧,写出更加健壮、高效和易于维护的代码。 本书以清晰、简洁的风格介绍了Java编程中的最佳实践和常见陷阱。通过深入的解释和实践经验,作者分享了大量有关类设计、方法设

    2024年04月17日
    浏览(39)
  • 如果在git配置中报错fatal: Authentication failed for ‘‘,其实就是凭证失败的意思

    1、首先你需要确认你的账号密码是否正确,或者近期修改过密码,我就是修改了密码,密码错误导致 2、查看凭证并修改凭证,步骤如下: a.打开控制面板中的---用户账号--凭据管理---windows凭据--编辑--保存(然后就可以重新执行你们前面报错的git配置啦, 比如我是git push报错

    2024年02月12日
    浏览(42)
  • Python开启线程和线程池的方法

    1、通过用户慢慢递增来进行性能压测,观察QPS(即每秒的响应请求数,也即是最大吞吐能力。),响应时间 2、根据公式计算:服务器端最佳线程数量=((线程等待时间+线程cpu时间)/线程cpu时间) * cpu数量 3、单用户压测,查看CPU的消耗,然后直接乘以百分比,再进行压测,一般这

    2024年02月03日
    浏览(44)
  • 【Linux】线程终结篇:线程池以及线程池的实现

    linux线程完结 文章目录 前言 一、线程池的实现 二、了解性知识 1.其他常见的各种锁 2.读者写者问题 总结 什么是线程池呢? 线程池一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行

    2024年02月12日
    浏览(35)
  • 线程池的核心线程数该怎么设置

    为什么要用线程池?线程池中的线程可以重复利用,避免了重复创建线程造成的资源开销。在线程的执行时间比较短,任务比较多的时候非常适合用线程池。 如果运行的线程少于核心线程,会尝试去开启一个新的核心线程(addWorker),如果有空间的核心线程,也不会去使用,

    2024年02月08日
    浏览(35)
  • 聊聊线程池的预热

    本文主要研究一下线程池的预热 java/util/concurrent/ThreadPoolExecutor.java ThreadPoolExecutor定义了prestartCoreThread,用于启动一个核心线程 java/util/concurrent/ThreadPoolExecutor.java prestartAllCoreThreads用于启动所有的核心线程 ThreadPoolExecutor提供了prestartCoreThread方法,用于启动一个核心线程,提供了

    2024年02月08日
    浏览(38)
  • python------线程池的应用

    在python中经常会使用异步,线程池,进程池,解决io操作,在爬虫中并不建议使用进程池(消耗过大) 目标:会使用线程池 1:导入 我们可以看到了只有在demo1完全运行完毕才会运行demo2,这个时候是单任务 2:基本使用方法 我们可以看到这时候2个线程的一起跑 3:线程池的基本使用步骤  

    2024年02月15日
    浏览(39)
  • 线程池的五种状态

    1、RUNNING 状态说明:线程池处于RUNNING状态时,能够接收新任务以及对已添加的任务进行处理。 状态切换:线程池的初始状态为RUNNING。换句话说线程池一旦被创建,就处于RUNNING状态,且线程池中的任务数为0 2、SHUTDOWN 状态说明:线程池处于SHUTDOWN状态时,不接收新任务,但能

    2023年04月09日
    浏览(73)
  • Java线程池的入门

    一、线程池的优势 1.降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗。 2.提高系统相应速度,当有任务到达时,通过复用已存在的行程,无需等待新线程的创建便能立刻执行。 3.方便线程并发数的管控,因为线程若是无限制创建,可能会导致内存

    2024年02月08日
    浏览(42)
  • Java多线程之线程池的参数和配置

    在Java多线程编程中,线程池是一种常见的技术,用于管理线程的创建和销毁。线程池中的线程可以被重复利用,从而减少了线程的创建和销毁的开销,提高了程序的性能。在Java中,线程池的参数和配置非常重要,不同的参数和配置会影响线程池的性能和行为。 Java线程池的主

    2024年02月16日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包