动态调整大小的线程池

时间:2012-08-09 13:16:26

标签: java parallel-processing threadpool

我的应用程序中有以下工作流程:可能有来自用户的X请求(通常是5-10个同时),他们希望在系统中搜索某些内容(每个请求都在一个单独的线程中处理)。

每个搜索都可以并行处理(我目前正在实施)。线程/ CPU使用率实际上不是问题,因为这些任务不是CPU密集型的。数据库是瓶颈。

目前我只为搜索机制设置了一个单独的数据库连接池 - 最大池大小设置为10.我知道这并不多,但我无法将其设置得更高。现在我想弄清楚如何为每个搜索设置线程池(每个用户)。

每个请求(线程)将产生一个单独的线程池(在此池中,每个线程将处理给定用户搜索的一部分)。将此线程池的大小设置为固定大小(假设为4)是非常有问题的,例如10个用户一次点击“搜索”按钮,因为它会产生10个线程池,每个线程4个线程= 40个线程,并且只有10个线程池中的数据库连接?我猜有些线程只是闲置而其余的会竞争获得池的连接,但这真的是一个巨大的问题吗?

如果是,那么最佳行动方案是什么:

  1. 在创建时检查已有多少个线程池 新的并相应地调整它(这个新池的)最大线程池大小(比如说 已经有2个池,每个池有4个线程,然后是新线程 创建时将最大线程设置为2,甚至更新的池,只允许1个最大线程)。这意味着每个下一个用户的搜索都会慢得多。
  2. 创建具有相同最大线程池大小(即4)的线程池,但实现我自己的线程池,该线程池将动态检查应用程序中有多少线程并相应地调整maxThreadPoolSize(在本例中为所有线程池, 2个旧的和新的,将缩小为3个线程)。这将要求每个线程池访问一些共享对象,该对象包含有关应用程序中所有线程池的信息。
  3. 别的什么?
  4. 修改 感谢所有评论/答案。为了澄清我为什么每个请求需要一个线程池 - 这样做,这样一个用户就不会用完整个线程池。流程完全如下:当用户点击“搜索”时,会生成一个对象列表(此列表的范围可以从1个项目到数千个),然后对每个项目执行数据库查找。现在它全部按顺序执行。在我的更改之后,每个任务处理一次查找(因为对DB的搜索非常慢,它给了我一个非常大的提升 - 我知道我可以尝试做一些DB微调,但我不负责它。)

    问题在于,如果我使用User1并对X000生成的项目执行非常通用的搜索,则可能需要几分钟(或更长时间)。所以我可以在一个用户的执行器中拥有数千个任务。然后,如果我有一个共享线程池,让我们说最多10个线程(与连接池相同的数字),这个请求将被放入线程池的队列中。现在,如果User2来并执行他的搜索,他将不得不等待User1的搜索完成,因为他的搜索将被放入同一个队列中。这是我想要通过每个请求的线程池避免的情况。

    我并不是真的害怕上下文切换,因为每次计算可能需要几秒钟,所以它们不会经常发生。

    目前我正在考虑共享线程池和每个用户线程将向其发送数据的管理器,然后管理器会在有空闲线程时将其发送到线程池。这样我就可以实现它(管理器)从不同用户发送任务(即没有一个用户不会支配线程池)。

    我用这种方法看到的问题是,我需要以某种方式通知“父线程”(意思是用户请求)管理员处理其所有任务并以某种方式将结果发送给它。

1 个答案:

答案 0 :(得分:1)

现代处理器很容易处理数百个线程没有问题,但正如@PeterLawrey所说,你的设计有些奇怪。如果如你所说,操作的计算成本不高,拥有非常多的线程将导致大量昂贵的上下文切换,从而导致性能下降。

额外的复杂性来自于您希望为每个请求创建一个线程池,而连接池是针对每个应用程序的:

  • 如果每个请求都有一个线程池,则每次获得新请求时都必须创建并销毁
  • 无论你想要100,000美元预算的数万亿的线程和超级计算机,不超过10个线程都会做有用的工作。

你的直觉现在应该告诉你问题是你想为每个请求一个线程池,而理想的解决方案是在请求中有一个共享线程池,线程数等于你的连接池大小。这将最大化线程重用。

如果您还想避免单个请求获取所有计算能力,您可能需要添加一个层来决定谁有权安排额外的工作。使用每个请求解决方案的线程池,您可以让调度程序为您执行此操作,这不是一个好主意,因为您无法控制算法。

相反,您可以实现自己的“公平算法”,例如通过PriorityBlockingQueue,其中具有较少数量的块的项目位于顶部,或者使用ConcurrentHashMap,其中为每个用户存储要计划的作业列表,以及谁已经回来等等。