Java多线程在长进程、最大CPU占用率下变慢

标签 java multithreading

我正在使用 Eclipse 开发一个 Java 程序,该程序可以分析大型物理数据集并运行迭代优化过程。在对特别大的数据集进行多次迭代测试时,我看到了一种无法解释的现象。

以下是线程的设置方式:

List<String> scenarios;    
List<Thread> threads = new ArrayList<Thread>();
final int cores = Runtime.getRuntime().availableProcessors() - 1;

for(final String scenario: scenarios) {
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                innerLoopParallel(); //each optimization iteration
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        if(threads.size() < cores) {
            thread.start();
            threads.add(thread);
        }
    }
    for (Thread thread: threads) {
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

我的机器有 8 个核心,我在其中 7 个核心上进行多线程处理。迭代过程一开始运行得非常快,然后在运行大约 20 分钟后速度明显减慢。我的第一个想法是内存限制,但我一直在关注堆状态(在 Eclipse 中,窗口 -> 首选项 -> 常规 -> “显示堆状态”),而且它似乎并没有达到最大值。然而,我的 CPU 已经达到极限(见图),风扇猛烈地吹着。在每次迭代中,它应该向控制台打印一行,但随着程序变慢,它开始分块写入,一次打印 20 行。

Max CPU Usage

我知道这个问题有点模糊,但我已经没有想法了。您有什么建议可以为我指明正确的方向吗?多线程会导致问题吗? for 循环是否有可能通过不关闭某些进程来以某种方式建立 CPU?如果您需要澄清任何问题,请随时提问。

最佳答案

Do you have any suggestions to point me in the right direction?

使用分析器来确定您的应用程序将所有时间都花在了哪里。

Could the multi-threading be causing an issue?

有可能。特别是如果您创建了太多线程和/或在线程之间进行了太多上下文切换。

Is it possible that a for-loop might build up CPU somehow by not closing some process?

这个问题(对我来说)确实没有意义。

但是 for 循环花费的时间可能会越来越长,因为它们操作的数据结构越来越大。随着时间的推移,算法可能会变得非常慢/CPU 密集型,还有许多其他可能的原因。

建议:

  • 分析您的代码/算法以及您使用线程的方式。
  • 考虑进行 Big O 复杂性分析。
  • 考虑您的应用程序是否因非本地化内存访问模式而导致过度内存争用和缓存抖动。

更新

我可以看到您的线程代码有问题。例如,看起来有些线程永远不会启动。但也有明显迹象1表明这不是真实代码,因此分析它的实用性值得怀疑。

但是我认为您应该使用带有有界线程池的 ExecutorService 或 fork join 池,而不是这样做。 (不确定哪一个最好......因为你的示例代码太抽象了。)自己进行线程池管理并不是一个好主意,而且已经有 20 多年了!

另一方面,没有任何真正的证据表明线程是问题所在。请参阅我之前的建议!

<小时/>

1 - 例如,监控显示有 >2500 个 native 线程。但您向我们展示的代码不应该发生这种情况。

关于Java多线程在长进程、最大CPU占用率下变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53310063/

相关文章:

java - Spring Flux缓存项是如何管理的

C# Mutex Timespan 向新手解释

C#多线程文件IO(阅读)

java - 在多线程环境中与 Java 服务器和 C# 客户端通信时出现管道损坏错误

造成循环继承的java观察者

java - 在 Android 中保存 Arraylist

java - 为什么代码会面临看到部分构造的对象的风险?

python - Tcl_AsyncDelete 错误多线程 Python

java - 我可以使用 lambda 表达式通过 CDI 的策略模式动态获取 ejb 吗?

java - Sqlite 插入无法正常工作