为什么我的 java 长 运行 线程(5k+ 线程)没有利用所有机器内核(12 个内核)?

Why my java long running Threads (5k+ thread) not utilizing all machines cores (12 cores)?

我写了一个简单的多线程 java 应用程序,main 方法只创建了 5k 个线程,每个线程将遍历一个包含 5M 条记录的列表来处理。

我的机器规格:

我的 jar 现在是 运行,我使用 hTop 监控我的应用程序,这是我在 运行

时可以看到的

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

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

Match.class

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+ :)

Based on my understanding if I have a multiThreaded process, it'll fully utilize all my cores until the task is completed.

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

so why the work load is only around 0.5 (only half a core is used)?

一些可能的原因:

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

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

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


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

My Target: to utilize all cores and get all this 5k+ done as fast as it can be :)

这两个目标可能互斥 :-)


All threads are logging to the same file by a the java.util.Logger.

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

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


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

猜测是低效的。

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

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