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

我试图在我的一个应用程序中使用执行程序服务,在该应用程序中我创建了8个池,因为我的机器具有4个内核,并且根据最近的搜索,我发现一个内核上只能有2个活动线程.
当我通过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核.

I found that only 2 active threads can work on a core

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

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

线程池

creating a pool of 500 when my cpu can handle only 8 threads.

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

What is the best way to create thread pool in java

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

在具有在功能的各个部分中进行的各种工作负载的应用程序中,维护多个线程池可能很有意义.使用线程数量很少的池来进行CPU密集型工作,而线程数量较多的池来进行CPU密集型工作.现代Java中的Executors框架有助于简化这一过程.

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

棘手的东西

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

必读:Brian Goetz等的Java Concurrency in Practice.

上一篇:Java并发编程,深度探索J.U.C - AQS


下一篇:ExecutorService