为什么我的java长时间运行的线程(5k +线程)没有使用所有机器核心(12核)?

Tam*_*leh 1 java multithreading htop

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

我的机器规格:

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

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

在此输入图像描述

这就是我构造一个Thread的方式:

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

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)
}
Run Code Online (Sandbox Code Playgroud)

现在我有一些问题:

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

2-为什么我的Java应用程序状态是"S"(休眠),而它实际运行并填满日志文件?

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

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

Ste*_*n C 6

根据我的理解,如果我有一个multiThreaded进程,它将完全利用我的所有核心,直到任务完成.

你的理解是不正确的.有很多原因可能导致核心不能(全部)用于设计不良的多线程应用程序.

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

可能的原因有很多:

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

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

鉴于你的线程正在取得一些进展,我认为解释#2非常适合你的"症状".


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

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

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


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

这可能导致他们所有人争夺同一个锁...在记录器框架中的某个东西.或者对日志文件的文件I/O进行瓶颈.

一般来说,伐木是昂贵的.如果您需要性能,请最小化日志记录,并且对于必须进行日志记录的情况,请使用不会引入并发瓶颈的日志记录框架.


解决这个问题的最好方法是分析代码并计算出大部分时间花在哪里.

猜测工作效率低下.