递归地将线程添加到Java线程池

ljb*_*ade 7 java concurrency multithreading threadpool

我正在为我的Java并发课程编写一个教程.目标是使用线程池并行计算素数.

该设计基于Eratosthenes的Sieve.它有一个n个bool数组,其中n是你要检查的最大整数,数组中的每个元素代表一个整数.True是素数,false是非素数,数组最初都是真的.

线程池使用固定数量的线程(我们应该试验池中的线程数并观察性能).

给一个线程一个整数倍来处理.然后线程找到数组中第一个不是线程整数倍数的真元素.然后,线程在线程池上创建一个新线程,该线程被赋予找到的号码.

形成新线程后,现有线程继续将数组中所有整数的整数设置为false.

主程序线程以整数'2'启动第一个线程,然后等待所有生成的线程完成.然后它会吐出素数和计算所需的时间.

我遇到的问题是线程池中的线程越多,1个线程最快的线程就越慢.它应该变得更快而不是更慢!

互联网上有关Java线程池的所有内容都会创建n个工作线程,然后主线程等待所有线程完成.我使用的方法是递归的,因为worker可以生成更多的工作线程.

我想知道出了什么问题,以及是否可以递归使用Java线程池.

Ste*_*n C 5

在为以下某些问题添加线程时,您的解决方案可能会运行得更慢:

  • 线程创建开销:创建线程很昂贵.

  • 处理器争用:如果有多个线程而不是处理器执行它们,则某些线程将被挂起,等待空闲处理器.结果是每个线程的平均处理速率下降.此外,操作系统需要对线程进行时间分片,这会消耗原本用于"真实"工作的时间.

  • 虚拟内存争用:每个线程都需要内存用于其堆栈.如果您的计算机没有足够的物理内存用于工作负载,则每个新的线程堆栈都会增加虚拟内存争用,从而导致分页速度降低

  • 缓存争用:每个线程(可能)将扫描阵列的不同部分,导致内存缓存未命中.这会减慢内存访问速度.

  • 锁争用:如果您的线程都在读取和更新共享阵列并使用synchronized一个锁对象来控制对阵列的访问,那么您可能会遇到锁争用.如果使用单个锁对象,则每个线程将花费大部分时间等待获取锁.最终结果是计算被有效地序列化,并且整体处理速率下降到单个处理器/线程的速率.

前四个问题是多线程所固有的,并且没有真正的解决方案......除了不创建太多线程并重用已经创建的线程.但是,有许多方法可以解决锁争用问题.例如,

  • 重新编码应用程序,以便每个线程扫描多个整数,但在其自己的数组部分.这将消除数组上的锁争用,但是您需要一种方法来告诉每个线程要做什么,并且需要考虑到争用.
  • 为阵列的不同区域创建一个锁数组,并让线程根据它们所操作的数组的区域选择要使用的锁.你仍然会得到争用,但平均而言你应该得到更少的争用.
  • 设计并实施无锁解决方案.这将需要深入了解Java内存模型.并且很难证明/证明无锁解决方案不包含细微的并发缺陷.

最后,线程的递归创建可能是一个错误,因为它将使实现线程重用和反锁争用措施变得更加困难.