使用 ThreadPoolExecutor 缩放 maxPoolSize;为什么池不动态增加其大小?

2024-01-08

作为初学者,我正在学习 java 中的线程和并发包,并且我已经阅读了有关 ThreadPoolExecutor 的文档来了解两者之间的差异getPoolSize(), getCorePoolSize(), getMaxPoolSize()并尝试在代码中实现相同的功能。

背景知识

据我了解,Executors.newFixedThreadPool(3)创建一个池 corePoolSize = 3,当我们继续通过池执行任务时,将创建线程直到 3,然后当底层队列大小达到 100 并且仍然提交新任务时,这就是 maxPoolSize 出现的地方,并且线程被缩放以从 corePoolSize 达到 maxPoolSize 现在。

public class Test {

    static ThreadPoolExecutor pool=(ThreadPoolExecutor)Executors.newFixedThreadPool(3);
    
    public static void main(String k[]) throws InterruptedException{
        BlockingQueue<Runnable> queue=pool.getQueue();
        pool.execute(()->{
            for(int b=0;b<10;b++)
                System.out.println("Hello "+b);
        });
        pool.execute(()->{
            for(int b=0;b<10;b++)
                System.out.println("Hello "+b);
        });
        pool.setMaximumPoolSize(10);  //Setting maxPoolSize
        
     for(int j=0;j<20000;j++)       
        pool.execute(()->{
            for(int b=0;b<100;b++){
                System.out.println("Hello "+b);
            System.out.println("Queue size "+queue.size()+" "+"and pool size "+pool.getPoolSize()); 
        }
    });
 }

当上面的程序执行时,我可以看到队列大小达到黑白12000-20000,如果是这种情况那么getPoolSize()必须打印大于 corePoolSize 的值,因为 maxPoolSize 设置为 10,但每次它只会打印 3(即 corePoolSize),为什么会发生这种情况?正如我们预期的那样,它会扩展到 maxPoolSize。


The Executors.newFixedThreadPool返回一个ExecutorService;一个不公开的接口(并且probably充分的理由)这样的方法setMaximumPoolSize and setCorePoolSize.

如果您创建一个类型池Executors.newFixedThreadPool,该池应在应用程序的生命周期内保持固定。如果你想要一个可以调整其大小的池,相应地,你应该使用Executors.newCachedThreadPool()反而。

根据我的理解,Executors.newFixedThreadPool(3) 创建一个池 与 corePoolSize-3 (...)

看看实施情况newFixedThreadPool可以看出:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

and

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

所以当你经过时3 to the Executors.newFixedThreadPool构造函数,你设置both the corePoolSizemaximumPoolSize to 3.

(...) 当我们继续通过池执行任务时,线程将被创建,直到 3 然后当底层队列大小达到100时又新增任务 仍然提交,这就是 maxPoolSize 发挥作用的地方 并且线程现在从 corePoolSize 扩展到 maxPoolSize。

其实这个说法不太准确,不过我稍后会详细解释。现在阅读 Java 文档Executors.newFixedThreadPool它指出:

创建一个线程池,重用固定数量的线程操作 脱离共享无界队列。在任何时候,最多 nThreads 个线程 将是主动处理任务。如果提交了额外的任务 当所有线程都处于活动状态时,他们将在队列中等待,直到 线程可用。

因此,池不会扩展(除非您明确这样做)。

当上面的程序执行时,我可以看到队列大小达到 黑白 12000-20000,如果是这种情况,则 getPoolSize() 必须打印 值大于 corePoolSize,因为 maxPoolSize 设置为 10,但是 每次它只会打印 3(即 corePoolSize)为什么会这样 发生什么?正如我们期望的那样,它会扩展到 maxPoolSize。

不,这不准确,如果您打印pool.getMaximumPoolSize()它会返回10正如预期的那样,调用pool.setMaximumPoolSize(10);不会改变 corePoolSize 大小。但是,如果你这样做pool.setCorePoolSize(10);您将增加池以能够处理10同时线程。

The this.maximumPoolSize只是定义了池应同时处理的线程数的上限,它不会更改池的当前大小。

为什么池不动态增加其大小?

稍微深入一点newFixedThreadPool实现中,可以看到Pool初始化了一个任务队列new LinkedBlockingQueue<Runnable>()大小等于Integer.MAX_VALUE。看方法execute人们可以在评论中读到以下内容:

/*
         * 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.
         */

如果仔细阅读第2点和第3点,可以推断出only当任务无法添加到队列时,池将创建比 corePoolSize 指定的线程更多的线程。并且自从Executors.newFixedThreadPool使用队列Integer.MAX_VALUE您无法看到池动态分配更多资源,除非显式设置corePoolSize with pool.setCorePoolSize.

所有这些都是人们不必关心的实现细节。因此,为什么Executors接口不公开方法,例如setMaximumPoolSize.

From 线程池执行器 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html可以阅读的文档:

核心和最大池大小

ThreadPoolExecutor 将自动调整池大小(请参阅 getPoolSize()) 根据 corePoolSize 设置的边界(参见 getCorePoolSize()) 和 MaximumPoolSize(请参阅 getMaximumPoolSize())。 当在方法execute(java.lang.Runnable)中提交新任务时, 并且运行的线程数少于 corePoolSize,则创建一个新线程 创建来处理请求,即使其他工作线程处于空闲状态。如果大于corePoolSize但小于maximumPoolSize 线程正在运行,只有当队列已满时才会创建新线程 满的。通过将 corePoolSize 和 MaximumPoolSize 设置为相同,您可以创建 固定大小的线程池。通过将 MaximumPoolSize 设置为本质上 无界值,例如 Integer.MAX_VALUE,您允许池 容纳任意数量的并发任务。最典型的是, 核心池和最大池大小仅在构建时设置,但它们 也可以使用 setCorePoolSize(int) 动态更改 设置最大池大小(int)。

这基本上证实了为什么池没有动态更新其大小。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 ThreadPoolExecutor 缩放 maxPoolSize;为什么池不动态增加其大小? 的相关文章

  • 实现与扩展:何时使用?有什么不同?

    请用易于理解的语言进行解释或提供某些文章的链接 extends is for 延伸一类 implements is for 实施一个接口 接口和常规类之间的区别在于 在接口中您不能实现任何声明的方法 只有 实现 接口的类才能实现方法 C 中
  • 在 IntelliJ 上进行 Google App Engine Java 开发?

    令人烦恼的是 Google App Engine 已成为其中的另一个项目 他们只发布 Eclipse 插件 如 Spring Webflow 而我更喜欢 IntelliJ 你能用IntelliJ成功运行本地测试环境吗 并调试 部署本地或实时
  • 使用 Android WebViewClient 启用特定 SSL 协议

    我的应用程序使用WebViewClient与服务器建立 SSL 连接 服务器配置为仅接受 TLSv1 1 及以上协议 使用 Android 时 如何检查哪些 SSL 协议是 a 支持的和 b 默认启用的WebViewClient在设备上 如
  • 如何测试调用父类的受保护(不需要的)方法的方法?

    我陷入了一个非常奇怪的情况 我有一些需要测试的特定代码 这里是 public class A The real method of real class is so big that I just don t want to test it
  • 如何在其他核心上运行每个线程?

    我有一个 udp 服务器接收数据并计算它 每个角色我都有两个线程 我的CPU是8个多核 我以不同的速度发送数据 但最多我只使用了 cpu 两核 50 的 14 如果我发送更多的数据值 我的缓冲区将填满并且不会使用更多的CPU 为什么每个核心
  • 要打乱的键值(整数、字符串)列表的最佳结构

    我需要在 Java 中实现一个结构 它是一个键值列表 类型为整数 字符串 并且我想对其进行洗牌 基本上 我想做类似的事情 public LinkedHashMap
  • 在 Hibernate 中创建 UPDATE RETURNING 查询

    在 Oracle 中 我们可以创建一个更新查询 该查询将使用 RETURNING 子句返回更新的记录 Hibernate中有类似的功能吗 除了数据库生成的值之外 Hibernate 显然不需要返回更新的实例 因为对象传递给Session s
  • 用 java 编写解释器时的 switch 或 if 语句

    当前的作业需要我编写一个程序 以一种非常微小且基本的编程语言 行为有点像 FORTRAN 来读取包含指令的文件并执行这些指令 基本上它是我猜的语言的简单解释器 它是完全线性的 所有语句都是按顺序定义的 并且只有字符串和整数变量 我需要查找和
  • 支持通过 OAuth 进行 Facebook/Twitter 身份验证的 CAS 服务器

    我正在寻找一个支持 Facebook Twitter 通过 OAuth 进行单点登录身份验证的 CAS 服务器 我检查过 JASIG CAS 服务器 但它看起来不支持它们 我的 java web 应用程序基于 Spring Security
  • Java 泛型:如何为泛型类型指定类类型?

    我有一个 POJO 指定为 MyClass u where U是泛型类型参数 我正在尝试编写一个接受类引用的实用方法Class u
  • 打印 jasper 文件时执行报表 SQL 语句时出错

    我修改了一个旧项目 但无法确定这段代码有什么问题 使用下面的 jrxml它创造 jasper文件 当我打印 jasper 文件时 使用此代码JasperPrint jasperPrint JasperFillManager fillRepo
  • Java元数据读写

    是否可以以通用方式 对于所有图像类型 在 Java 中读取和写入元数据 我找到了一些示例 但它们总是特定的 例如 JPEG 或 PNG 我需要一些足够通用的东西 而不是到处都有 if else 语句 我不想重写源代码 但这是一个很好的例子
  • Java:使用 Java.util.concurrent 线程访问读取线程串行端口

    我正在尝试编写一个 Java 串行设备驱动程序并想使用 对我来说是新的 java util concurrent包裹 我有一种发送数据包然后等待 ACK 的方法 我打算有炭 接收在不同的线程中运行 如果接收线程收到 ACK 它应该使用发送数
  • 在 eclipse 之外将 Spring MVC 应用程序部署到 tomcat 的幕后会发生什么?

    我猜想使用像 eclipse 这样很棒的 IDE 的一个缺点是你会忽略应用程序幕后发生的事情 我是一名 Ruby 开发人员 所以不是一名 Java 老手 所以我一直在用 java 编写一个项目 并使用 spring 框架进行 IOC 和 M
  • 使用Java开发跨平台,不同平台字体缩放不同

    我正在为我的大学制作一些软件 需要一个 GUI 在它的第一个版本中 我让它使用系统外观 因此它看起来像 Linux Mac Windows 中的本机应用程序 我发现这很麻烦 因为我必须根据操作系统使所有 JLabel 具有不同的大小 无论分
  • 为什么现在()? (客观化)

    为什么我想要异步加载 Objectify 实体 异步加载到底意味着什么 根据客观化有关加载的文档 https code google com p objectify appengine wiki BasicOperations Loadin
  • 战争库中的罐子爆炸

    我们可以将分解的 jar 文件放入 war web inf 库中吗 它在 JBOSS 4 2 中对我不起作用 我收到以下错误并且无法部署应用程序 Caused by javax management RuntimeOperationsExc
  • 在服务器内部调用 Web 服务

    我有一个网络服务 getEmployee 当传递 id 时 它会获取单个员工的员工详细信息 同一服务器上的另一个 Web 服务 getEmployeeList 当传递一个部门时 它会获取整个员工列表 这将获取部门的 ID 然后调用 getE
  • 如何使用剪辑来减少绘画时间?

    我正在尝试使用 Clip 来减少 CPU 负载 但剪辑在屏幕上留下了一些我似乎无法摆脱的垃圾 另外 打开和关闭剪辑似乎对 CPU 负载没有影响 在任一情况下 大部分时间似乎都花在重绘管理器和绘制缓冲图像上 import static jav
  • 我找不到 IntelliJ 快捷方式

    我使用 vim 一段时间 我知道有一个 intellij vim 插件 我很好奇内置的 IntelliJ 文本导航存在什么 如何打开实时模板来创建模板 如何查看以 tr 开头的现有模板列表 如何进行全局搜索并在当前文档中进行搜索 然后转到下

随机推荐