In putting together a "state sampling" monitor (periodically wake up and inquire about the state of application threads known to the JVM), I came upon something troubling, and perhaps unavoidable.
The issue is quite simple:
a. call ThreadMXBean.getThreadInfo to populate a ThreadInfo for threads I find interesting (my application's threads).
b. iterate over this array calling a few of the ThreadInfo methods (e.g., getThreadId, getThreadName, getThreadState).
c. find a thread in BLOCKED state (Thread.State)
d. try to inquire further about the blocked thread, e.g., call getLockInfo
But by the time (d) fires, the thread is no longer in BLOCKED state and the call to getLockInfo returns null.
I think I need some kind of "snapshot" of the entirety of thread state. I mean something that will return a picture of the thread at a given point in time; and NOT require me to call methods that query the live thread.
1. of what use is ThreadInfo in a situation like this?
2. is there some way of obtaining the "snapshot" I described?
Are you using ThreadInfo getThreadInfo(long ids, boolean lockedMonitors, boolean lockedSynchronizers) method (passing true as the second and third parameter)? I use this when I need to dump as detailed information as possible (basically, in my deadlock detector thread ) and was always able to pin down the problem from that.
Joined: Feb 25, 2012
Thanks for the reply.
I am using not the variant of getThreadInfo that you describe. Rather, I am using
I had looked at the variant you recommend, but wasn't sure if it accomplishes what I want. If I understand the API docs correctly, using
does not give me information about what the thread is waiting on (see ThreadInfo.getLockInfo()). Rather, it shows me monitors and ownable synchronizers that are "currently locked by the thread." My goal is to try to figure exactly what a waiting thread is waiting on.
This whole issure arose as I executed this code:
I get NPEs in these calls if the target thread (represented by the ThreadInfo variable ti) has ended. So it seemed to me that the array of ThreadInfo objects returned by the call to getThreadInfo did NOT, as I had hoped, contain all of the state needed to resolve the calls inside the for loop. That is, those calls might require interrogating the thread itself. Such interrogation against a dead thread leads to the NPE.
This behavior, which can only occur at thread termination, got me thinking more generally about the relationship between the ThreadInfo object and the actual Thread instance. And it was here that the more troubling concern arose, namely that I couldn't be sure that the ThreadInfo was consistent with the current state of the thread, i.e., its state after the getThreadInfo() call completes. Specifically, if ThreadInfo.getThreadState() shows me Thread.State of BLOCKED, will a subsequent call to ThreadInfo.getLockInfo() return the LockInfo object that the thread was BLOCKED on at the time of the getThreadInfo() call; or, because the the thread is now RUNNABLE, will it return null?
Thank you for considering this matter. I find this issue troubling and would like to get to the bottom of it without having to resort to a JVMTI approach.
When I call toString() on the ThreadInfo obtained the way I've described, I get this:
Do you need more detailed output?
Anyway, I've had a look at the ThreadInfo source in the JDK, and it does not seem to be accessing live threads; everything comes from fields initialized by constructors. I don't see how the state of the thread after ThreadInfo has been constructed could change any of its values...
I think the Javadoc does not clearly state anything about internal consistency, and I would consider the possibility that neither of these method creates consistent snapshot. You might be able to find more info on the internet, or prove there is inconsistency by analyzing the output (eg. a thread waiting on a lock no one else owns).
Doh! The cause of your NPEs is actually quite clear from the Javadoc:
This method returns an array of the ThreadInfo objects, each is the thread information about the thread with the same index as in the ids array. If a thread of the given ID is not alive or does not exist, null will be set in the corresponding element in the returned array. A thread is alive if it has been started and has not yet died.
Joined: Feb 25, 2012
Ah, screw-up (misinterpretation) on my part.
Thanks again, Martin.
Joined: Feb 25, 2012
Follow up question for you, Martin:
In using this form
do you then follow it with a call to ThreadInfo.getStackTrace() ?
Put otherwise, where does the information you displayed come from, e.g.,
"Thread-6" Id=28 BLOCKED on java.lang.Object@1fc7b3a owned by "Thread-5" Id=27
- blocked on java.lang.Object@1fc7b3a
- locked java.lang.Object@fe2509
at java.lang.Thread.run(Unknown Source)