1

我写了一个简单的多线程 java 应用程序,主要方法只是创建 5k 个线程,每个线程将循环遍历一个有 5M 记录要处理的列表。

我的机器规格:

  • CPU核数:12核
  • 内存:13Gb RAM
  • 操作系统:Debian 64 位

我的 jar 现在正在运行,我使用 hTop 来监视我的应用程序,这是我在运行时可以看到的

在此处输入图像描述

这就是我构建线程的方式:

ExecutorService executor = Executors.newCachedThreadPool();
Future<MatchResult> future = executor.submit(() -> {
            Match match = new Match();
            return match.find(this);
        });

匹配类

find(Main main){
// looping over a list of 5M 
// process this values and doing some calculations 
// send the result back to the caller 
// this function has no problem and it just takes a long time to run (~160 min)
}

现在我有一些问题:

1-根据我的理解,如果我有一个多线程进程,它将充分利用我所有的内核直到任务完成,那么为什么工作负载只有0.5左右(只使用了半个内核)?

2- 为什么我的 Java 应用程序在实际运行并填充日志文件时状态为“S”(睡眠)?

3- 为什么我只能看到 5k 中的 2037 个线程正在运行(这个数字实际上比这个少,并且随着时间的推移而增加)

我的目标:利用所有内核并尽可能快地完成所有这 5k+ :)

4

2 回答 2

6

根据我的理解,如果我有一个多线程进程,它将充分利用我的所有内核,直到任务完成。

你的理解不正确。在设计不佳的多线程应用程序中可能无法(全部)使用内核的原因有很多。

那为什么工作量只有0.5左右(只用了半个核心)?

一些可能的原因:

  1. 线程可能会死锁。
  2. 线程可能都在争夺一个锁(或少数锁),导致它们中的大多数都在等待。
  3. 线程可能都在等待 I/O;例如从某个数据库中读取记录。

这些只是一些更明显的可能原因。

鉴于您的线程正在取得一些进展,我认为解释 #2 非常适合您的“症状”。


对于它的价值,创建 5k 线程几乎可以肯定是一个非常糟糕的主意。其中最多有 12 个可能随时运行。其余的将等待运行(假设您解决了导致线程不足的问题)并占用内存。后者具有各种次要性能效果。

我的目标:利用所有内核并尽可能快地完成所有这 5k+ :)

这两个目标可能是相互排斥的:-)


所有线程都通过 java.util.Logger 记录到同一个文件。

这可能导致他们都争夺同一个锁......在记录器框架中的某个东西上。或者日志文件的文件 I/O 出现瓶颈。

一般来说,日志记录是昂贵的。如果您想要性能,请尽量减少您的日志记录,对于日志记录必不可少的情况,请使用不会引入并发瓶颈的日志记录框架。


解决这个问题的最好方法是分析代码并找出它花费大部分时间的地方。

猜测是低效的。

于 2018-02-10T07:47:48.353 回答
1

谢谢你们,我已经解决了这个问题,现在我有 12 个核心运行到最大,如图所示。:)

在此处输入图像描述

我实际上尝试运行这个命令jstack <Pid>来查看这个进程ID中我所有正在运行的线程的状态,我发现我的95%的线程实际上是在该logging行被BLOCKED,我做了一些谷歌搜索,发现我可以在log4J中使用AsynchAppender所以日志不会阻塞线程

于 2018-02-10T12:56:43.307 回答