public
Last active

find out the correspondence between the tid/nid of Java threads as shown from jstack/JMX, on HotSpot/Linux

  • Download Gist
PrintThreadIds.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
package fx.jvm.hotspot.tools;
 
import java.util.List;
 
import sun.jvm.hotspot.tools.Tool;
 
public class PrintThreadIds extends Tool {
public static void main(String[] args) {
PrintThreadIds tool = new PrintThreadIds();
tool.start(args);
tool.stop();
}
 
@Override
public void run() {
List<ThreadInfo> infos = ThreadUtils.getAllThreadInfos();
for (ThreadInfo info : infos) {
System.out.printf("Thread@%s: tid=%d nid=0x%x\n",
info.getAddress(), info.getTid(), info.getNid());
}
}
}
README.md
Markdown

In HotSpot, a Java thread may have a couple of different IDs, depending on the context.

Java-level thread ID

This ID could be fetched from java.lang.Thread.getId() or java.lang.management.ThreadMXBean.getAllThreadIds(). It's platform independent.

In Oracle/Sun's JDK implementation, this ID is simply a auto-incrementing long, starting from 1, assigned to each Java-level java.lang.Thread object when they're initialized.

Quote from java.lang.management.ThreadMXBean's JavaDoc:

Thread ID

Thread ID is a positive long value returned by calling the Thread.getId() method for a thread. The thread ID is unique during its lifetime. When a thread is terminated, this thread ID may be reused.

Some methods in this interface take a thread ID or an array of thread IDs as the input parameter and return per-thread information.

Native thread ID

This ID is highly platform dependent. It's the nid in jstack thread dumps.

  • On Windows, it's simply the OS-level thread ID within a process.

  • On Linux, it's the pid of the thread (which in turn is a light-weight process).

  • On Solaris, it's the thread as returned by thr_self().

  • On Mac OS X, it is said to be the native pthread_t value.

The Address of a C++-level Thread/JavaThread object

This is also platform dependent. It's the tid in jstack thread dumps.

The valid stack memory region of a JavaThread

In JavaThread::print_on(outputStream*) const:

  // print guess for valid stack memory region (assume 4K pages); helps lock debugging
  st->print_cr("[" INTPTR_FORMAT "]", (intptr_t)last_Java_sp() & ~right_n_bits(12));

That's the last pair of brackets in a jstack output for Java threads. If it's showing "0x0000000000000000", then last_Java_sp == NULL, which means there is no last Java frame for this thread.

The correspondence? Serviceability Agent to the rescue

See the Java source files in this gist. To compile them, Project Lombok's lombok.jar and JDK's sa-jdi.jar are required on classpath.

Sample (1) a running Groovy shell retrieving Java-level thread IDs
1 2 3 4 5 6 7 8 9 10 11 12 13
[sajia@v036122 experiment]$ groovysh
Groovy Shell (1.7.7, JVM: 1.6.0_25-ea)
Type 'help' or '\h' for help.
-------------------------------------------------------------------------------------------------------------------------------------
groovy:000> import java.lang.management.ManagementFactory
===> [import java.lang.management.ManagementFactory]
groovy:000> threadMXBean = ManagementFactory.threadMXBean
===> sun.management.ThreadImpl@1966c114
groovy:000> threadMXBean.allThreadIds
===> [J@69408a75
groovy:000> println threadMXBean.allThreadIds
[19, 12, 10, 4, 3, 2, 1]
===> null
Sample (2) a jstack thread dump of that Groovy shell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
[sajia@v036122 satest]$ jstack 32133
2011-02-25 17:16:52
Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.0-b08 mixed mode):
 
"Attach Listener" daemon prio=10 tid=0x0000000060460000 nid=0x7dc8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
 
"Thread-4" daemon prio=10 tid=0x00002aaab4041000 nid=0x7d9f in Object.wait() [0x000000004167c000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebf0120> (a java.util.LinkedList)
at java.lang.Object.wait(Object.java:485)
at java.util.prefs.AbstractPreferences$EventDispatchThread.run(AbstractPreferences.java:1461)
- locked <0x00000000eebf0120> (a java.util.LinkedList)
 
"Timer-0" daemon prio=10 tid=0x00002aaab4063800 nid=0x7d9e in Object.wait() [0x0000000040df7000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebf01b0> (a java.util.TaskQueue)
at java.util.TimerThread.mainLoop(Timer.java:509)
- locked <0x00000000eebf01b0> (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:462)
 
"Low Memory Detector" daemon prio=10 tid=0x000000005f804000 nid=0x7d9c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
 
"C2 CompilerThread1" daemon prio=10 tid=0x000000005f802000 nid=0x7d9b waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
 
"C2 CompilerThread0" daemon prio=10 tid=0x000000005f7fc800 nid=0x7d9a waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
 
"Signal Dispatcher" daemon prio=10 tid=0x000000005f7fa000 nid=0x7d99 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
 
"Finalizer" daemon prio=10 tid=0x000000005f7d6000 nid=0x7d98 in Object.wait() [0x0000000042286000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebfa8a8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
- locked <0x00000000eebfa8a8> (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=0x000000005f7d4000 nid=0x7d97 in Object.wait() [0x0000000042185000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebfa840> (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 <0x00000000eebfa840> (a java.lang.ref.Reference$Lock)
 
"main" prio=10 tid=0x000000005f772000 nid=0x7d91 runnable [0x0000000040204000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:220)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read(BufferedInputStream.java:237)
- locked <0x00000000eedb8f60> (a java.io.BufferedInputStream)
at jline.Terminal.readCharacter(Terminal.java:99)
at jline.UnixTerminal.readVirtualKey(UnixTerminal.java:128)
at jline.ConsoleReader.readVirtualKey(ConsoleReader.java:1453)
at jline.ConsoleReader.readBinding(ConsoleReader.java:654)
at jline.ConsoleReader.readLine(ConsoleReader.java:494)
at jline.ConsoleReader.readLine(ConsoleReader.java:448)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:229)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
at org.codehaus.groovy.tools.shell.InteractiveShellRunner.readLine(InteractiveShellRunner.groovy:87)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:145)
at org.codehaus.groovy.tools.shell.ShellRunner.work(ShellRunner.groovy:75)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:145)
at org.codehaus.groovy.tools.shell.ShellRunner.run(ShellRunner.groovy:57)
at org.codehaus.groovy.tools.shell.InteractiveShellRunner.super$2$run(InteractiveShellRunner.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:88)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1058)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuperN(ScriptBytecodeAdapter.java:127)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuper0(ScriptBytecodeAdapter.java:147)
at org.codehaus.groovy.tools.shell.InteractiveShellRunner.run(InteractiveShellRunner.groovy:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:63)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
at org.codehaus.groovy.tools.shell.Groovysh.run(Groovysh.groovy:442)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:225)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:149)
at org.codehaus.groovy.tools.shell.Groovysh.run(Groovysh.groovy:381)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:225)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:63)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
at org.codehaus.groovy.tools.shell.Main.main(Main.groovy:132)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:108)
at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:130)
 
"VM Thread" prio=10 tid=0x000000005f7cf800 nid=0x7d96 runnable
 
"GC task thread#0 (ParallelGC)" prio=10 tid=0x000000005f785000 nid=0x7d92 runnable
 
"GC task thread#1 (ParallelGC)" prio=10 tid=0x000000005f787000 nid=0x7d93 runnable
 
"GC task thread#2 (ParallelGC)" prio=10 tid=0x000000005f788800 nid=0x7d94 runnable
 
"GC task thread#3 (ParallelGC)" prio=10 tid=0x000000005f78a800 nid=0x7d95 runnable
 
"VM Periodic Task Thread" prio=10 tid=0x000000005f80f000 nid=0x7d9d waiting on condition
 
JNI global references: 1539
Sample (3) getting the correspondence between those IDs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[sajia@v036122 satest]$ java -classpath .:$JAVA_HOME/lib/sa-jdi.jar fx.jvm.hotspot.tools.PrintThreadIds 32133
Attaching to process ID 32133, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.0-b08
Thread@0x0000000060460000: tid=19 nid=0x7dc8
Thread@0x00002aaab4041000: tid=12 nid=0x7d9f
Thread@0x00002aaab4063800: tid=10 nid=0x7d9e
Thread@0x000000005f804000: tid=7 nid=0x7d9c
Thread@0x000000005f802000: tid=6 nid=0x7d9b
Thread@0x000000005f7fc800: tid=5 nid=0x7d9a
Thread@0x000000005f7fa000: tid=4 nid=0x7d99
Thread@0x000000005f7d6000: tid=3 nid=0x7d98
Thread@0x000000005f7d4000: tid=2 nid=0x7d97
Thread@0x000000005f772000: tid=1 nid=0x7d91
Sample: (1) a running Groovy shell, retrieving Java-level thread IDs
1 2 3 4 5 6 7 8 9 10 11 12 13
[sajia@v036122 experiment]$ groovysh
Groovy Shell (1.7.7, JVM: 1.6.0_25-ea)
Type 'help' or '\h' for help.
-------------------------------------------------------------------------------------------------------------------------------------
groovy:000> import java.lang.management.ManagementFactory
===> [import java.lang.management.ManagementFactory]
groovy:000> threadMXBean = ManagementFactory.threadMXBean
===> sun.management.ThreadImpl@1966c114
groovy:000> threadMXBean.allThreadIds
===> [J@69408a75
groovy:000> println threadMXBean.allThreadIds
[19, 12, 10, 4, 3, 2, 1]
===> null
Sample: (2) a jstack thread dump of that Groovy shell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
[sajia@v036122 satest]$ jstack 32133
2011-02-25 17:16:52
Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.0-b08 mixed mode):
 
"Attach Listener" daemon prio=10 tid=0x0000000060460000 nid=0x7dc8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
 
"Thread-4" daemon prio=10 tid=0x00002aaab4041000 nid=0x7d9f in Object.wait() [0x000000004167c000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebf0120> (a java.util.LinkedList)
at java.lang.Object.wait(Object.java:485)
at java.util.prefs.AbstractPreferences$EventDispatchThread.run(AbstractPreferences.java:1461)
- locked <0x00000000eebf0120> (a java.util.LinkedList)
 
"Timer-0" daemon prio=10 tid=0x00002aaab4063800 nid=0x7d9e in Object.wait() [0x0000000040df7000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebf01b0> (a java.util.TaskQueue)
at java.util.TimerThread.mainLoop(Timer.java:509)
- locked <0x00000000eebf01b0> (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:462)
 
"Low Memory Detector" daemon prio=10 tid=0x000000005f804000 nid=0x7d9c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
 
"C2 CompilerThread1" daemon prio=10 tid=0x000000005f802000 nid=0x7d9b waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
 
"C2 CompilerThread0" daemon prio=10 tid=0x000000005f7fc800 nid=0x7d9a waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
 
"Signal Dispatcher" daemon prio=10 tid=0x000000005f7fa000 nid=0x7d99 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
 
"Finalizer" daemon prio=10 tid=0x000000005f7d6000 nid=0x7d98 in Object.wait() [0x0000000042286000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebfa8a8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
- locked <0x00000000eebfa8a8> (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=0x000000005f7d4000 nid=0x7d97 in Object.wait() [0x0000000042185000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebfa840> (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 <0x00000000eebfa840> (a java.lang.ref.Reference$Lock)
 
"main" prio=10 tid=0x000000005f772000 nid=0x7d91 runnable [0x0000000040204000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:220)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read(BufferedInputStream.java:237)
- locked <0x00000000eedb8f60> (a java.io.BufferedInputStream)
at jline.Terminal.readCharacter(Terminal.java:99)
at jline.UnixTerminal.readVirtualKey(UnixTerminal.java:128)
at jline.ConsoleReader.readVirtualKey(ConsoleReader.java:1453)
at jline.ConsoleReader.readBinding(ConsoleReader.java:654)
at jline.ConsoleReader.readLine(ConsoleReader.java:494)
at jline.ConsoleReader.readLine(ConsoleReader.java:448)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:229)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
at org.codehaus.groovy.tools.shell.InteractiveShellRunner.readLine(InteractiveShellRunner.groovy:87)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:145)
at org.codehaus.groovy.tools.shell.ShellRunner.work(ShellRunner.groovy:75)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:145)
at org.codehaus.groovy.tools.shell.ShellRunner.run(ShellRunner.groovy:57)
at org.codehaus.groovy.tools.shell.InteractiveShellRunner.super$2$run(InteractiveShellRunner.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:88)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1058)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuperN(ScriptBytecodeAdapter.java:127)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuper0(ScriptBytecodeAdapter.java:147)
at org.codehaus.groovy.tools.shell.InteractiveShellRunner.run(InteractiveShellRunner.groovy:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:63)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
at org.codehaus.groovy.tools.shell.Groovysh.run(Groovysh.groovy:442)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:225)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:149)
at org.codehaus.groovy.tools.shell.Groovysh.run(Groovysh.groovy:381)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:225)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:63)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
at org.codehaus.groovy.tools.shell.Main.main(Main.groovy:132)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:108)
at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:130)
 
"VM Thread" prio=10 tid=0x000000005f7cf800 nid=0x7d96 runnable
 
"GC task thread#0 (ParallelGC)" prio=10 tid=0x000000005f785000 nid=0x7d92 runnable
 
"GC task thread#1 (ParallelGC)" prio=10 tid=0x000000005f787000 nid=0x7d93 runnable
 
"GC task thread#2 (ParallelGC)" prio=10 tid=0x000000005f788800 nid=0x7d94 runnable
 
"GC task thread#3 (ParallelGC)" prio=10 tid=0x000000005f78a800 nid=0x7d95 runnable
 
"VM Periodic Task Thread" prio=10 tid=0x000000005f80f000 nid=0x7d9d waiting on condition
 
JNI global references: 1539
Sample: (3) getting the correspondence between those IDs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[sajia@v036122 satest]$ java -classpath .:$JAVA_HOME/lib/sa-jdi.jar fx.jvm.hotspot.tools.PrintThreadIds 32133
Attaching to process ID 32133, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.0-b08
Thread@0x0000000060460000: tid=19 nid=0x7dc8
Thread@0x00002aaab4041000: tid=12 nid=0x7d9f
Thread@0x00002aaab4063800: tid=10 nid=0x7d9e
Thread@0x000000005f804000: tid=7 nid=0x7d9c
Thread@0x000000005f802000: tid=6 nid=0x7d9b
Thread@0x000000005f7fc800: tid=5 nid=0x7d9a
Thread@0x000000005f7fa000: tid=4 nid=0x7d99
Thread@0x000000005f7d6000: tid=3 nid=0x7d98
Thread@0x000000005f7d4000: tid=2 nid=0x7d97
Thread@0x000000005f772000: tid=1 nid=0x7d91
ThreadInfo.java
Java
1 2 3 4 5 6 7 8 9 10 11
package fx.jvm.hotspot.tools;
 
import lombok.Data;
import sun.jvm.hotspot.debugger.Address;
 
@Data(staticConstructor="of")
public class ThreadInfo {
private final Address address;
private final long tid;
private final long nid;
}
ThreadUtils.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
package fx.jvm.hotspot.tools;
 
import java.util.ArrayList;
import java.util.List;
 
import sun.jvm.hotspot.debugger.Address;
import sun.jvm.hotspot.oops.Field;
import sun.jvm.hotspot.oops.InstanceKlass;
import sun.jvm.hotspot.oops.Klass;
import sun.jvm.hotspot.oops.LongField;
import sun.jvm.hotspot.oops.Oop;
import sun.jvm.hotspot.runtime.JavaThread;
import sun.jvm.hotspot.runtime.Threads;
import sun.jvm.hotspot.runtime.VM;
 
public class ThreadUtils {
public static List<ThreadInfo> getAllThreadInfos() {
List<ThreadInfo> infos = new ArrayList<ThreadInfo>();
Threads threads = VM.getVM().getThreads();
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
Address address = thread.getAddress();
long tid = getTid(thread);
long nid = Long.parseLong(thread.getThreadProxy().toString());
infos.add(ThreadInfo.of(address, tid, nid));
}
return infos;
}
public static long getTid(JavaThread thread) {
final long BAD_TID = -1L;
Oop threadObj = thread.getThreadObj();
Klass klass = threadObj.getKlass();
if (!(klass instanceof InstanceKlass)) return BAD_TID;
InstanceKlass instanceKlass = (InstanceKlass) klass;
Field tidField = instanceKlass.findField("tid", TypeCode.LONG);
if (!(tidField instanceof LongField)) return BAD_TID;
long tid = ((LongField) tidField).getValue(threadObj);
return tid;
 
}
}
TypeCode.java
Java
1 2 3 4 5 6 7 8 9 10 11 12
package fx.jvm.hotspot.tools;
 
public interface TypeCode {
String BOOLEAN = "Z";
String BYTE = "B";
String CHAR = "C";
String SHORT = "S";
String INT = "I";
String LONG = "J";
String FLOAT = "F";
String DOUBLE = "D";
}

Hi, one thing I am not very clear is what you said about nid:

On Linux and Solaris, it's the pid of the thread (which in turn is a light-weight process).

In Solaris, one process may have many light weight processes(http://java.sun.com/docs/hotspot/threads/threads.html), which lwp ids are you referring? From what you said, it sounds like a pid is the same as lwp id, but they are not the same right?

Hi tinybyte,

The nid on Solaris is the thread ID returned by thr_self(). Does that answer your question?

HotSpot VM keeps these two fields in its Solaris version of OSThread implementation:

  thread_t _thread_id;      // Solaris thread id
  unsigned int  _lwp_id;    // lwp ID, only used with bound threads

nid in jstack is the _thread_id value. I'm sorry if I made any confusion in this gist. Thank you for the question :-)

A related changeset in OpenJDK:

http://hg.openjdk.java.net/hsx/hotspot-rt/hotspot/rev/0368109684cb

7132070: Use a mach_port_t as the OSThread thread_id rather than pthread_t on BSD/OSX

Summary: Change OSThread to use mach thread_t

Great stuff. Just verified on Windows7 (Where 'nid' matches native HANDLE of corresponding OS thread).

Thanks,
Andy

Thanks for sharing. It's really helpful.

Tina

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.