我试图在我的一个应用程序中使用执行程序服务,在该应用程序中我创建了8个池,因为我的机器具有4个内核,并且根据最近的搜索,我发现一个内核上只能有2个活动线程。 当我通过java检查内核数时,也发现该值为4
int cores = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(cores*2);
请建议我做的是否正确,因为当我的cpu只能处理8个线程时,我看不出有太多的价值创建500个池。
答案 0 :(得分:2)
您应该阅读hyper-threading技术。该术语专门用于Intel用于其专有的simultaneous multithreading (SMT)实现的品牌名称,但更广泛地用于SMT。
过于简单的解释:
在常规CPU中,线程之间的切换非常昂贵。寄存器是CPU内核实际处理的几条数据的存放地。切换线程时,必须将这些寄存器中的值换出。同样,也可以清除缓存(保存数据的位置,比寄存器慢,但比RAM快)。这一切都需要时间。
CPU中的超线程设计会添加一组重复的寄存器。每个内核都有一组寄存器,这意味着它可以在线程之间切换而无需交换寄存器中的值。线程之间的切换要快得多,以至于CPU依赖于操作系统,将每个内核报告为一对(虚拟)内核。例如,一个4核芯片将显示为8核。
我发现一个核心上只能有2个活动线程
请注意,切换线程仍然有一些开销,而开销却低得多。超线程CPU内核一次仍仅执行一个线程。超线程意味着线程之间的切换更加轻松快捷。
对于在线程通常处于等待模式的机器上,等待某些外部功能(例如通过网络调用)完成的机器,超线程非常有意义。对于内核可能会执行CPU限制的工作(例如数字运算,模拟,科学数据分析)的应用程序,那么超线程可能没有那么有用。因此,在执行此类工作的计算机上,系统管理员可能会决定禁用超线程,因此4个内核实际上只是4个内核。同样,由于与超线程技术有关的recent security vulnerabilities,一些系统管理员可能会决定禁用超线程。
当我的CPU仅能处理8个线程时,创建500个池。
线程池的大小取决于您应用程序的行为。如果具有与CPU绑定的应用程序,那么您当然希望将此类CPU密集型线程的数量限制为少于实际或虚拟内核的数量。如果您的应用程序不受CPU限制,如果它们经常执行file I/O,网络I / O或其他活动,而它们在等待其他资源时却无所作为,那么您的线程数可能会比内核数多。如果您的线程经常闲置无事,那么您可以拥有更多线程。
在Java中创建线程池的最佳方法是什么
此处没有没有具体规则可以帮助您。您必须首先进行有根据的猜测,然后在生产中监视您的应用和主机。因此,您可能需要一种方法来设置运行时在应用程序中使用的线程数,而不是对数字进行硬编码。例如,使用首选项设置或使用JMX。学习使用诸如Java Flight Recorder和Mission Control之类的分析工具;两者现在都与基于OpenJDK的Java发行版捆绑在一起。如果您要部署到支持DTrace的系统(macOS,BSD等),这也可能会有所帮助。
在一个具有在不同功能部分中进行的各种工作负载的应用程序中,维护多个线程池可能很有意义。使用线程数量很少的池来进行CPU密集型工作,而线程数量更多的池来进行CPU密集型工作。现代Java中的Executors框架可以简化这一过程。
考虑所有您可能要部署到计算机上的应用程序。并考虑该计算机上运行的所有其他应用程序。并考虑到操作系统的CPU需求。这样做之后,您可能会发现某些线程池最多只能设置为一个或两个线程。
线程安全性是一项非常棘手的复杂工作。在线程(变量,文件等)之间共享资源时,您必须教育自己有关保护这些资源免遭滥用的问题。
答案 1 :(得分:0)
转到System properties
并检查其中有多少cores (physical cores)
和logical processors (virtual cores)
。
例如:
如果您的系统具有 n个内核 和 n个逻辑处理器 。这意味着您的处理器不支持hyperthreading
。
如果您的系统具有 n个内核 和 n x 2个逻辑处理器 。这意味着您的处理器支持hyperthreading
。您可以并行执行n * 2个线程。
注意:假设您具有超线程支持。现在,您有8个核心和16个虚拟核心。
然后,处理器将提供高达16个线程的良好吞吐量。如果将线程池增加到超过16个线程,吞吐量将变得均匀并且不会变化太多。