哪个Java线程占用CPU?

假设你的Java程序占用了100%的CPU。 它有50个线程。 你需要find哪个线程有罪。 我还没有find可以帮助的工具。 目前我使用以下非常耗时的程序:

  1. 运行jstack <pid> ,其中pid是Java进程的进程标识。 find它的简单方法是运行包含在JDK- jps中的另一个实用程序。 将jstack的输出redirect到一个文件是最好的。
  2. search“可运行”线程。 跳过那些在套接字上等待(由于某些原因,它们仍然标记为可运行)。
  3. 重复步骤1和2几次,看看你是否可以find一个模式。

或者,您可以在Eclipse中附加Java进程,并尝试一个接一个地挂起线程,直到您碰到CPU。 在单CPU机器上,您可能需要首先减lessJava进程的优先级,以便能够移动。 即使如此,由于超时,Eclipse常常无法附加到正在运行的进程。

我会期望Sun的visualvm工具来做到这一点。

有人知道更好的方法吗?

尝试查看可视VM的Hot Thread Detector插件 – 它使用ThreadMXBean API来获取多个CPU消耗示例以查找最活跃的线程。 它基于一个与布鲁斯·查普曼(Bruce Chapman)相当的命令行 ,可能也是有用的。

确定哪个Java线程占用了生产服务器中的大部分CPU。

大多数(如果不是全部的话)生产系统做任何重要的事情都会使用多于一个的java线程。 当某些事情变得疯狂,并且你的CPU使用率达到100%时,很难确定哪个线程正在造成这种情况。 或者我想。 直到有人比我更聪明的向我展示了如何做到这一点。 在这里,我将告诉你如何做到这一点,你也可以用你的极客技能惊讶你的家人和朋友。

testing应用程序

为了testing这个,我们需要一个testing应用程序。 所以我会给你一个。 它由3个类组成:

  • 执行CPU密集型HeavyThread类(计算MD5散列)
  • 一个LightThread类,它执行的不是CPU密集型(计数和睡眠)。
  • 一个StartThreads类启动1个cpu密集型和几个轻型线程。

这里是这些类的代码:

 import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.UUID; /** * thread that does some heavy lifting * * @author srasul * */ public class HeavyThread implements Runnable { private long length; public HeavyThread(long length) { this.length = length; new Thread(this).start(); } @Override public void run() { while (true) { String data = ""; // make some stuff up for (int i = 0; i < length; i++) { data += UUID.randomUUID().toString(); } MessageDigest digest; try { digest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } // hash the data digest.update(data.getBytes()); } } } import java.util.Random; /** * thread that does little work. just count & sleep * * @author srasul * */ public class LightThread implements Runnable { public LightThread() { new Thread(this).start(); } @Override public void run() { Long l = 0l; while(true) { l++; try { Thread.sleep(new Random().nextInt(10)); } catch (InterruptedException e) { e.printStackTrace(); } if(l == Long.MAX_VALUE) { l = 0l; } } } } /** * start it all * * @author srasul * */ public class StartThreads { public static void main(String[] args) { // lets start 1 heavy ... new HeavyThread(1000); // ... and 3 light threads new LightThread(); new LightThread(); new LightThread(); } } 

假设你从来没有见过这个代码,并且你有一个运行这些类的失控Java进程的PID,并且正在占用100%的CPU。

首先让我们开始StartThreads类。

 $ ls HeavyThread.java LightThread.java StartThreads.java $ javac * $ java StartThreads & 

在这个阶段,一个正在运行的Java进程应该占用100个CPU。 在我的顶部,我看到: 顶级输出的屏幕截图

在顶部按Shift-H打开线程。 顶部的手册页说:

  -H : Threads toggle Starts top with the last remembered 'H' state reversed. When this toggle is On, all individual threads will be displayed. Otherwise, top displays a summation of all threads in a process. 

现在我的线程显示打开我看: 显示线程的顶部屏幕截图

我有一个PID过程与28294java进程。 让我们使用jstack获取这个进程的堆栈转储:

 $ jstack 28924 2010-11-18 13:05:41 Full thread dump Java HotSpot(TM) 64-Bit Server VM (17.0-b16 mixed mode): "Attach Listener" daemon prio=10 tid=0x0000000040ecb000 nid=0x7150 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "DestroyJavaVM" prio=10 tid=0x00007f9a98027800 nid=0x70fd waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Thread-3" prio=10 tid=0x00007f9a98025800 nid=0x710d waiting on condition [0x00007f9a9d543000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at LightThread.run(LightThread.java:21) at java.lang.Thread.run(Thread.java:619) "Thread-2" prio=10 tid=0x00007f9a98023800 nid=0x710c waiting on condition [0x00007f9a9d644000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at LightThread.run(LightThread.java:21) at java.lang.Thread.run(Thread.java:619) "Thread-1" prio=10 tid=0x00007f9a98021800 nid=0x710b waiting on condition [0x00007f9a9d745000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at LightThread.run(LightThread.java:21) at java.lang.Thread.run(Thread.java:619) "Thread-0" prio=10 tid=0x00007f9a98020000 nid=0x710a runnable [0x00007f9a9d846000] java.lang.Thread.State: RUNNABLE at sun.security.provider.DigestBase.engineReset(DigestBase.java:139) at sun.security.provider.DigestBase.engineUpdate(DigestBase.java:104) at java.security.MessageDigest$Delegate.engineUpdate(MessageDigest.java:538) at java.security.MessageDigest.update(MessageDigest.java:293) at sun.security.provider.SecureRandom.engineNextBytes(SecureRandom.java:197) - locked <0x00007f9aa457e400> (a sun.security.provider.SecureRandom) at sun.security.provider.NativePRNG$RandomIO.implNextBytes(NativePRNG.java:257) - locked <0x00007f9aa457e708> (a java.lang.Object) at sun.security.provider.NativePRNG$RandomIO.access$200(NativePRNG.java:108) at sun.security.provider.NativePRNG.engineNextBytes(NativePRNG.java:97) at java.security.SecureRandom.nextBytes(SecureRandom.java:433) - locked <0x00007f9aa4582fc8> (a java.security.SecureRandom) at java.util.UUID.randomUUID(UUID.java:162) at HeavyThread.run(HeavyThread.java:27) at java.lang.Thread.run(Thread.java:619) "Low Memory Detector" daemon prio=10 tid=0x00007f9a98006800 nid=0x7108 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "CompilerThread1" daemon prio=10 tid=0x00007f9a98004000 nid=0x7107 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "CompilerThread0" daemon prio=10 tid=0x00007f9a98001000 nid=0x7106 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Signal Dispatcher" daemon prio=10 tid=0x0000000040de4000 nid=0x7105 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Finalizer" daemon prio=10 tid=0x0000000040dc4800 nid=0x7104 in Object.wait() [0x00007f9a97ffe000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00007f9aa45506b0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118) - locked <0x00007f9aa45506b0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159) "Reference Handler" daemon prio=10 tid=0x0000000040dbd000 nid=0x7103 in Object.wait() [0x00007f9a9de92000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00007f9aa4550318> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:485) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116) - locked <0x00007f9aa4550318> (a java.lang.ref.Reference$Lock) "VM Thread" prio=10 tid=0x0000000040db8800 nid=0x7102 runnable "GC task thread#0 (ParallelGC)" prio=10 tid=0x0000000040d6e800 nid=0x70fe runnable "GC task thread#1 (ParallelGC)" prio=10 tid=0x0000000040d70800 nid=0x70ff runnable "GC task thread#2 (ParallelGC)" prio=10 tid=0x0000000040d72000 nid=0x7100 runnable "GC task thread#3 (ParallelGC)" prio=10 tid=0x0000000040d74000 nid=0x7101 runnable "VM Periodic Task Thread" prio=10 tid=0x00007f9a98011800 nid=0x7109 waiting on condition JNI global references: 910 

从我的顶部我看到顶线的PID是28938 。 hex中的0x710A0x710A 。 请注意,在堆栈转储中,每个线程都有一个以hex显示的nid 。 而0x710A是线程的ID:

 "Thread-0" prio=10 tid=0x00007f9a98020000 nid=0x710a runnable [0x00007f9a9d846000] java.lang.Thread.State: RUNNABLE at sun.security.provider.DigestBase.engineReset(DigestBase.java:139) at sun.security.provider.DigestBase.engineUpdate(DigestBase.java:104) at java.security.MessageDigest$Delegate.engineUpdate(MessageDigest.java:538) at java.security.MessageDigest.update(MessageDigest.java:293) at sun.security.provider.SecureRandom.engineNextBytes(SecureRandom.java:197) - locked <0x00007f9aa457e400> (a sun.security.provider.SecureRandom) at sun.security.provider.NativePRNG$RandomIO.implNextBytes(NativePRNG.java:257) - locked <0x00007f9aa457e708> (a java.lang.Object) at sun.security.provider.NativePRNG$RandomIO.access$200(NativePRNG.java:108) at sun.security.provider.NativePRNG.engineNextBytes(NativePRNG.java:97) at java.security.SecureRandom.nextBytes(SecureRandom.java:433) - locked <0x00007f9aa4582fc8> (a java.security.SecureRandom) at java.util.UUID.randomUUID(UUID.java:162) at HeavyThread.run(HeavyThread.java:27) at java.lang.Thread.run(Thread.java:619) 

因此,您可以确认正在运行HeavyThread类的线程正在占用大部分CPU。

在阅读世界的情况下,可能会有一堆线程占用CPU的一部分,这些线程放在一起会导致使用100%CPU的Java进程。

概要

  • 运行顶部
  • 按Shift-H启用线程视图
  • 获取最高CPU的线程的PID
  • 将PID转换为HEX
  • 获取java进程的堆栈转储
  • 寻找与HEX PID匹配的线程。

jvmtop可以显示您最重要的线程:

  TID NAME STATE CPU TOTALCPU 25 http-8080-Processor13 RUNNABLE 4.55% 1.60% 128022 RMI TCP Connection(18)-10.101. RUNNABLE 1.82% 0.02% 36578 http-8080-Processor164 RUNNABLE 0.91% 2.35% 128026 JMX server connection timeout TIMED_WAITING 0.00% 0.00% 

只需运行JVisualVM,连接到您的应用程序,然后使用线程视图。 一直保持活跃的是你最可能的罪魁祸首。

查看JConsole的Top Threads插件。

如果您在Windows下运行,请尝试Process Explorer 。 调出您的过程的属性对话框,然后select线程选项卡。

采取线程转储。 等待10秒。 采取另一个线程转储。 重复一次。 检查线程转储,看看哪些线程卡在同一个地方,或处理相同的请求。 这是一个手动的方式,但通常是有用的。

你在多核计算机上运行Java 6吗?

有机会,你正在遭遇我刚刚在一篇关于线程匮乏的文章中所描述的问题。

看到同步与锁与公平锁 。

这是一种很冒险的方式,但是好像你可以在debugging器中启动应用程序,然后暂停所有的线程,并且通过代码找出哪一个没有被锁或I / O在某种循环中调用。 或者这就像你已经尝试过的?

您可以考虑的选项是从应用程序中查询您的主题以获取答案。 通过ThreadMXBean,您可以从Java应用程序中查询线程的CPU使用情况,并查询有问题的线程的堆栈跟踪。

ThreadMXBean选项允许您在实时应用程序中构build这种监视。 它具有微不足道的影响,并具有明显的优势,您可以使其完全按照您的要求进行。

如果您怀疑VisualVM是一个很好的工具,那就试试吧(因为它是这样的)找出这个线程只会帮助您了解为什么它会消耗这么多的CPU。

但是,如果它很明显,我会直接使用探查器来找出为什么你消耗这么多的CPU。