【问题标题】:Maximum number of threads than can run concurrently in java on a CPU可以在 CPU 上的 java 中同时运行的最大线程数
【发布时间】:2014-03-06 04:23:51
【问题描述】:

我对某事感到困惑。 我所知道的是,现代计算机的普通 CPU 上可以同时运行的最大线程数为 8 到 16 个线程。 另一方面,使用 GPU 可以同时运行数千个线程,而无需调度程序中断任何线程来调度另一个线程。 在几个职位上: Java virtual machine - maximum number of threadshttps://community.oracle.com/message/10312772 人们说他们在普通 CPU 上同时运行数千个 java 线程。 这怎么可能?? 以及如何知道可以同时运行的最大线程数,以便我的代码根据底层架构自行动态调整。

【问题讨论】:

  • 理论上您可以运行任意数量的程序,但您会遇到越来越多的开销,因为 JVM 难以跟踪调度。

标签: java multithreading gpu cpu


【解决方案1】:

线程不受可用处理器/内核数量的限制或限制。操作系统调度程序可以在单个 CPU 上的任意数量的线程之间来回切换。这就是“抢占式多任务”的含义。

当然,如果您的线程数多于内核数,则并非所有线程都会同时执行。有些会被搁置,等待一个时间段。

实际上,您可以拥有的线程数受到调度程序的限制 - 但这个数字通常非常高(数千或更多)。它会因操作系统和各个版本而异。

就性能角度而言有用的线程数,正如您所说,这取决于可用处理器的数量以及任务是否受 IO 或 CPU 限制。尝试找到最佳数量并尽可能使其可配置。

【讨论】:

  • '当然,如果你的线程比核心多' - 你的意思是'当然,如果你的 READY 线程比核心多'。
  • 只是为了好玩:我可以在 Windows 7 x64 下使用默认线程堆栈大小创建的最大线程数使用STACK_SIZE_PARAM_IS_A_RESERVATION 确保只有最小内存必要的实际提交是大约 72k 和 8gb 内存。
【解决方案2】:

存在硬件和软件并发。 8 到 16 个线程是指您拥有的硬件 - 即一个或多个具有硬件的 CPU,用于执行彼此并行的 8 到 16 个线程。数千个线程是指软件线程的数量,调度程序必须将它们交换出去,以便每个软件线程都有时间片在硬件上运行。

要获取硬件线程数,您可以尝试Runtime.availableProcessors()

【讨论】:

  • 除非通过硬件或软件中断进入操作系统,否则调度程序将不执行任何操作。 “数千个线程”大多没有准备好运行,因此不需要任何“时间片”在硬件上运行。
  • @MartinJames 除非您的操作系统在协作线程上运行,否则总会有一个 cpu 计时器通过硬件中断触发调度程序。线程是否准备好运行取决于它们所做的事情,如果它们所做的只是睡眠,那么拥有数千个线程仍然是浪费的(每个线程都有一个堆栈和管理结构)。
  • 可以在没有定时器中断的情况下运行抢占式多任务操作系统。启动调度程序运行的其他方法,即来自磁盘的中断、NIC、KB、鼠标和来自 I/O 请求的软件中断和线程间同步非常重要。定时器只是另一个中断源,忽略其余的就是不好的。
  • 另外 - 你知道堆栈是可交换的吗?
  • @MartinJames 只要准备运行的线程总是少于可用的硬件,那么使用计时器是正确的,一旦获得更多,某些进程可能会饿死。关于堆栈问题:堆栈占用内存,数千个线程很快就会占用 2 GB 或更多,而将它们交换出去只会使切换回来的速度变慢。
【解决方案3】:

在任何给定时间,处理器将运行的线程数等于包含的内核数。这意味着在单处理器系统上,在任何给定时刻只有一个线程(或没有线程)正在运行。

但是,处理器不会一个接一个地运行每个线程,而是在多个线程之间快速切换以模拟并发执行。如果不是这种情况,更不用说创建多个线程,您甚至无法启动多个应用程序。

Java 线程(与处理器指令相比)是供 CPU 处理的一组指令的高级抽象。当它下降到处理器级别时,无法保证在任何给定时间哪些线程将在哪个内核上运行。但鉴于处理器在这些线程之间快速切换,理论上可以创建无限数量的线程,尽管会以性能为代价。

如果您考虑一下,现代计算机有数千个线程同时运行(结合所有应用程序),而只有 1 ~ 16 个(典型情况)内核数。如果没有这种任务切换,什么都做不了。

如果您正在优化您的应用程序,您应该考虑手头工作所需的线程数量,而不是底层架构。并行性带来的性能提升应该与增加的线程执行开销相权衡。由于每台机器都不同,每个运行时环境也不同,因此计算出一些黄金线程数是不切实际的(但是,可以通过基准测试和查看内核数量来进行大致估计)。

【讨论】:

  • '这意味着在单处理器系统上,在任何给定时刻只有一个线程正在运行' - 更像是'一个线程或没有线程'。
  • @MartinJames 答案已修复。
【解决方案4】:

虽然所有其他答案都解释了理论上如何在应用程序中拥有数千个线程,但以内存和其他开销为代价已经很好地解释了here。但是值得注意的是,java.util.concurrent 包中提供的数据结构的默认 concurrencyLevel 是 16。

如果您不考虑相同的问题,您会遇到争用问题。

使用显着高于所需的值会浪费空间和时间,而显着降低的值会导致线程争用。

确保您已设置适当的concurrencyLevel,以防遇到与更多线程并发相关的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多