gpt4 book ai didi

java - 是什么导致多线程程序在切换线程时挂起?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:54:12 24 4
gpt4 key购买 nike

我有一个多线程程序,它的线程数可以自定义。该程序负责生成 HTTP 请求,将请求发送到 Web 服务,接收响应并解析响应以获得一些结果值。

由于每次请求到得到响应大约需要1秒,为了让程序尽可能多的得到响应,开启了多线程。

以下代码用于启动多线程:

    ...
for (int i = 0; i < threadNum; i++) {
threadArray[i] = new Thread(requestGeneratorArray[i]);
threadArray[i].start();
}

for (int i = 0; i < threadNum; i++) {
try {
threadArray[i].join();
} catch (InterruptedException e) {
logger.error(e);
}
}

...

当线程数为50时,总共产生并发送了10K个请求,程序运行良好。当线程数还是50,总请求数是100K的时候。发送 95K+ 请求时程序挂起。没有异常(exception),程序只是卡在那里。

然后我添加了一些这样的 JVM 参数:java -Xmx1024M -Xms512M -XX:MaxPermSize=256m ... 有了这些参数,50 个线程/100K 请求就可以工作了。但是,50 个线程/1M 请求再次挂起。我将线程数设置为 20,将请求数设置为 1M,它再次起作用。

我想将线程数设置为50,因为在较少的请求数(10K)下测试,50个线程效率最高。请求数可能大得多,如 10M、100M、事件 1B。在这种情况下,增加 -Xmx -Xms 或 MaxPermSize 的大小并不是一个好主意。我应该怎么办?程序挂起的根本原因是什么?

============================================= ============

我直接使用了Executor Service而不是threads。但是问题也出现了。我重新检查了代码,发现有一个错误:我为每个请求实例化了一个 HttpClient 对象。我更改了代码,为每个线程实例化一个 HttpClient 实例,程序不再挂起。

我认为程序挂起的根本原因是它与网络服务建立了太多的 HTTP 连接,并用完了网络服务的所有线程。这使得 Web 服务无法响应任何新到达的请求。这是对的吗?

最佳答案

仅从这些信息很难判断,但从您的堆设置影响结果的事实来看,我敢打赌内容生成和内容解析(存储)之间的调度不佳。

这种应用程序中的一个常见场景是,生成内容的线程的生成速度比获取内容并将其存储的线程的生成速度更快。这将逐渐增加用于在内存中保存内容的堆内存量,并且在某些时候吞吐量将开始直线下降。

首先要做的是通过附加像 VisualVM 这样的堆查看器来确认这个假设。如果您的堆使用量逐渐增加并开始固定在高水平并且您的吞吐量下降,这可能是罪魁祸首(您可以还可以确认内存中的东西确实是生成的内容)。

通常,瓶颈是用于存储内容的持久层的 IO。您可能在解析代码(或其他地方)中遇到 CPU 瓶颈,具体取决于您的代码在做什么,但这通常很少见。

针对这种情况最常见的补救方法是使用有界队列让生成进程等待解析(存储)进程 catch 。看看这个 SO 答案:How to make ThreadPoolExecutor's submit() method block if it is saturated? .您将不得不了解线程池,但它确实是对原始线程的巨大改进,而且它是处理此类问题的最干净的方法。

关于java - 是什么导致多线程程序在切换线程时挂起?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14109016/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com