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

时间:2018-02-10 06:53:43

标签: java multithreading htop

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

我的机器规格:

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

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

enter image description here

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

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应用程序状态是&#34; S&#34; (睡觉)当它实际运行并填满日志文件?

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

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

2 个答案:

答案 0 :(得分:6)

  

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

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

  

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

有很多可能的原因:

  1. 线程可能已陷入僵局。
  2. 线程可能都争用一个锁(或少量锁),导致大多数人等待。
  3. 线程都可以等待I / O;例如从某个数据库中读取记录。
  4. 这些只是一些可能的原因。

    鉴于您的线程正在进行某些进展,我认为解释#2非常适合您的症状&#34;。

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

      

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

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

      

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

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

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

    解决此问题的最佳方法是配置代码并计算出大部分时间消耗的位置。

    猜测工作效率低下。

答案 1 :(得分:1)

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

enter image description here

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