java - 可动态调整大小的线程池

标签 java parallel-processing threadpool

我的应用程序中包含以下工作流程:可能有来自X个用户的请求(通常是5-10个),这些用户想要在系统中进行搜索(每个请求都在单独的线程中处理)。

每个搜索都可以并行处理(我目前正在实现)。这里的线程/ CPU使用率并不是真正的问题,因为这些任务不需要占用大量CPU资源。数据库是瓶颈。

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

每个请求(线程)将产生一个单独的线程池(并且在该池中,每个线程将处理给定用户搜索的一部分)。如果将例如10个用户一次按下“搜索”按钮,将这个线程池的大小设置为固定大小(让我们说4个)确实是有问题的,因为它将产生10个线程池,每个线程池有4个线程= 40个线程,而只有10个线程池中的数据库连接?我猜有些线程将只是空闲,其余线程将争夺连接池的连接,但这真的会是一个大问题吗?

如果是,那么最好的行动方案是:


在创建线程库时检查已经有多少个线程池
新线程,并相应地调整其(此新池的)最大线程池大小(例如
已经有2个池,每个池有4个线程,那么新的池将
创建时将最大线程数设置为2,甚至可以说仅使用1个最大线程来更新池)。这将意味着每个下一个用户的搜索将显着变慢。
创建具有相同最大线程池大小(即4)的线程池,但实现我自己的线程池,该线程池将动态检查应用程序中有多少线程,并相应地调整maxThreadPoolSize的大小(在这种情况下,例如所有线程池,两个旧的线程池)而新的则缩小为3个线程)。这将要求每个线程池访问某些共享对象,这些共享对象包含有关应用程序中所有线程池的信息。
还有什么吗


编辑:
感谢您的所有评论/答案。为了弄清楚为什么我希望每个请求都有一个线程池-这样做是为了使一个用户不会用完整个线程池。流程完全像这样:当用户单击“搜索”时,将生成一个对象列表(此列表的范围从1项到数千项),然后针对每个项执行DB查找。现在,所有这些操作都是顺序执行的。更改后,每个任务都会处理一次查找(因为在DB上的搜索非常慢,这给了我很大的推动-我知道我可以尝试做一些DB的微调,但我不负责)。

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

我并不是真的担心上下文切换,因为每个计算可能需要花费几秒钟的时间,因此它们不会经常发生。

当前,我正在考虑一个共享线程池和一个管理器,每个用户线程将向其发送数据,然后只要有空闲线程,该管理器便会将其发送到线程池。通过这种方式,我可以实现它(管理器)以从不同的用户发送任务(即,没有一个用户可以控制线程池)。

我看到的这种方法的问题是,我需要以某种方式告知“父线程”(即用户请求)其所有任务均由管理器处理,并以某种方式发送结果。

最佳答案

现代处理器可以轻松处理数百个线程而没有问题,但是正如@PeterLawrey所建议的那样,您的设计有些奇怪。如您所说,如果该操作在计算上并不昂贵,那么拥有大量线程将导致大量昂贵的上下文切换,从而导致性能下降。

额外的复杂性来自以下事实:您希望每个请求都有一个线程池,而连接池是针对每个应用程序的:


如果每个请求都有一个线程池,则必须创建它并在每次收到新请求时销毁它
无论您拥有数万亿的线程和拥有100000美元预算的超级计算机,最多可以有10个线程在做有用的工作。


您的直觉现在应该告诉您问题是您希望每个请求都有一个线程池,而理想的解决方案是在请求之间拥有一个共享线程池,并且线程数等于您的连接池大小。这将最大程度地重用线程。

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

取而代之的是,您可以实现自己的“公平算法”,例如通过PriorityBlockingQueue将块数量较少的项目移到顶部,或者使用ConcurrentHashMap为每个用户存储要调度的作业列表以及已经存储的作业列表。返回等等。

关于java - 可动态调整大小的线程池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11884327/

相关文章:

c# - Parallel.ForEach 花费的时间比预期的多

java - MongoDB java API 聚合 $lookup 和管道使用变量

java - Collectors.toSet 实现细节

java - 使用 Swing 的 Java 图形用户界面

Python(或一般的 linux)文件操作流控制或文件锁定

java - 有没有办法取消并重用ExecutorService?

java - 奇怪的 ForkJoinPool 行为

java - 如何在 Mac 上使用终端从 Eclipse 编译 Java 程序

python - numba @jit 比纯 python 慢?

c++ - 指针警告(并行计算)