java - 在Java中创建线程池的最佳方法是什么

标签 java executorservice

我试图在我的一个应用程序中使用执行程序服务,在该应用程序中我创建了8个池,因为我的机器有4个内核,并且根据最近的搜索,我发现一个内核上只能有2个 Activity 线程。
当我通过java检查内核数时,也发现该值为4

int cores = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(cores*2);

请建议我做得正确,因为当我的cpu只能处理8个线程时,我看不出创建500个池的价值。

最佳答案

超线程

您应该阅读hyper-threading技术。该术语专门用于英特尔专有的simultaneous multithreading (SMT)实现中使用的商标名称,但更广泛地用于SMT。

过于简单的解释:

在传统的CPU中,线程之间的切换非常昂贵。寄存器是CPU内核实际处理的几条数据的存放地。切换线程时,必须将这些寄存器中的值换出。同样,也可以清除缓存(保存数据的位置,比寄存器慢,但比RAM快)。这一切都需要时间。

CPU中的超线程设计会添加一组重复的寄存器。每个内核都有一组寄存器,这意味着它可以在线程之间切换而无需交换寄存器中的值。线程之间的切换要快得多,以至于CPU依赖于操作系统,将每个内核报告为一对(虚拟)内核。例如,一个4核芯片将显示为8核。

我发现只有2个 Activity 线程可以在一个核心上工作

请注意,切换线程仍然有一些开销,而开销却低得多。超线程CPU内核一次仍仅执行一个线程。超线程意味着线程之间的切换更加轻松快捷。

对于使用线程经常处于等待模式,等待某些外部功能(例如通过网络调用)完成的机器,超线程非常有意义。对于内核可能正在执行CPU限制的工作(例如数字运算,模拟,科学数据分析)的应用程序,超线程可能没有用。因此,在执行此类工作的计算机上,系统管理员可能会决定禁用超线程,因此4个内核实际上只是4个内核。另外,由于与超线程技术有关的recent security vulnerabilities,一些系统管理员可能会决定禁用超线程。

线程池

当我的cpu只能处理8个线程时,创建500个池。

线程池的大小取决于应用程序的行为。如果具有与CPU绑定的应用程序,那么您当然希望将此类CPU密集型线程的数量限制为少于实际或虚拟内核的数量。如果您的应用程序不受CPU限制,如果它们经常执行file I/O,网络I / O或其他 Activity ,而这些 Activity 在等待其他资源时通常不执行任何操作,那么您可以拥有比内核更多的线程。如果您的线程经常闲置无事,那么您可以拥有更多线程。

在Java中创建线程池的最佳方法是什么

这里没有,没有具体规则可以帮助您。您必须首先进行有根据的猜测,然后在生产中监视您的应用程序和主机。因此,您可能需要一种方法来设置运行时在应用程序中使用的线程数,而不是对数字进行硬编码。例如,使用首选项设置或使用JMX。学习使用分析工具,例如Java Flight RecorderMission Control;两者现在都与基于OpenJDK的Java发行版捆绑在一起。如果要部署到支持DTrace的系统(macOS,BSD等),这也可能会有所帮助。

在具有在功能的各个部分中进行的各种工作负载的应用程序中,维护多个线程池可能是有意义的。请使用线程数量很少的池来进行CPU密集型工作,而使用线程数量较多的池来进行CPU密集型工作。现代Java中的Executors框架使此操作变得容易。

考虑到您可能要部署到计算机上的所有应用程序。并考虑该计算机上运行的所有其他应用程序。并考虑到操作系统的CPU需求。完成所有这些操作后,您可能会发现某些线程池最多只能设置为一个或两个线程。

棘手的东西

线程安全是一项非常棘手的复杂工作。在线程(变量,文件等)之间共享资源时,您必须教育自己有关保护这些资源免遭滥用的问题。

必读:Java Concurrency in Practice等人撰写的Brian Goetz

关于java - 在Java中创建线程池的最佳方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56536007/

相关文章:

java - 重用Java定时器timertask

java - JDK 库是否提供 lambda 'invoker' 实用程序类?

java - 在 ExecutorService 的提交和 ExecutorService 的执行之间进行选择

java - 如何关闭等待中的服务器?

java - 如何并行处理文件的行?

java - 每次运行 Android 应用程序都会崩溃

java - 使用 EJB 3 将 'Text' 字段数据类型插入 MySQL

java - Java 执行器中无界队列的用例是什么?

java - ThreadPoolExecutor 中的submit(Callable<T> task) 方法

java - 使用 JAXB 交叉引用来自两个 XML 文件的 XmlID