ThreadMXBean - A Singleton MXBean for a Sleepless Night
By daniel on Jan 13, 2006
The flu has been plaguing me for a week, and last night I couldn't find sleep. So at 3am in the morning, I gave up. I switched on the light, grabbed a pen and a wad of paper, and started writing about the ThreadMXBean.
Actually the ThreadMXBean is more like a pretext, and what I really wanted to do - besides writing me to sleep, was talking about modeling with JMX, and laying out the ground for a coupled of further entries that I'm planning to write. In his blog, Eamonn McManus has already begun to write about modeling guidelines. ThreadMXBean is in fact a perfect example of non trivial design decisions which provide interesting insights on modeling issues. But let's start at the beginning.
One of the great new feature that was introduced in
Java SE 5.0 (Tiger)
Monitoring and Management API (to make it shorter: M&M).
The M&M API exposes MBeans that build up the management interface of the JVM itself. Among the objects that needed to be managed by this interface were Threads. The MBean that provides management and monitoring over Threads is the ThreadMXBean. Here is a question that's often been asked about the ThreadMXBean:
Why does the M&M API expose a single MBean, providing access to all threads, rather than simply exposing one MBean per thread? Wouldn't this have been simpler?
Well - you might already have your own idea about that, but you will see that we will find more reasons than simple performance issues.
- First, having a single MBean makes it possible to provide data that's been aggregated over all threads.
- Second thing, is that having a single ThreadMXBean makes it possible to expose a single well known ObjectName: java.lang:type=Threading.
- There's a ready to use public static constant for that ObjectName. So you don't need to be constantly constructing ObjectNames, dealing with MalformedObjectNameException.
- The managing application doesn't need to perform any MBeanServer.queryNames() operation with ObjectName patterns in order to learn about existing threads. It can simply ask the ThreadMXBean with its well known MBean name, etc...
- Then, having a single ThreadMXBean makes it possible to return a coherent snapshot of (a) thread(s) data in the instance of (a) ThreadInfo object(s).
- Further, having a single ThreadMXBean brings a definitive performance advantage to the implementation of the M&M API.
- Creating the MBean itself
- Creating the MBean's ObjectName
- Registering the MBean in the MBeanServer - which could take more or less time depending on how many MBeans are already registered
- Creating and sending the MBeanServerNotification for this MBean creation
- And we're not even speaking about the impact on footprint...
The ThreadMXBean offers methods like getDaemonThreadCount(), getPeakThreadCount(), findMonitorDeadlockedThreads(), etc... which is higher value aggregated information that naturally finds its place on an MBean that provides management and monitoring for all threads.
This might not strike you as such a big deal at first, but it does have several advantages: mainly that the code you have to write in the managing application is often much simpler.
Had we registered one MBean per thread, without taking care of data consistency, we might have ended up exposing uncorrelated pieces of thread information in the form of uncorrelated MBean attributes.
With a single MBean, the M&M API doesn't need to perform any operation on threads if none is explicitly requested by a management application. Had we chosen to model Threads as individual MBeans, the M&M API would have needed to monitor the creation/deletion of threads, just for the purpose of registering/deregistering the associated MBeans. Registering/deregistering MBeans can be a costly process since it involves in particular:
But then you might ask, what if I precisely wanted to receive a notification when a new thread was created, or a thread was terminated? What if I wanted to be able to register for AttributeChangedNotification in order to monitor the state of a a thread? Aren't those natural MBean operations, and doesn't this imply that Threads should have been MBeans?
Well, not necessarily, because there's none of these actions that couldn't be implemented also through the ThreadMXBean singleton. Had we had these requirements, nothing would have prevented us from making the ThreadMXBean emit notifications about thread creation/termination, or about state changes.
I believe it would even be easier for the managing application, which could register a single listener with the ThreadMXBean to get thread related notifications, rather than having to register its listener with the MBeanServerDelegate, and figure, e.g. with an ObjectName pattern, whether the MBean pointed to by the MBeanServerNotification is an MBean representing a thread or some other kind of MBean...
As you may have figured by reading these lines, there is more about designing a management interface than to force-feeding your application objects into MBeans. In a next blog yet to come (hopefully not through a sleepless night) I'll try explaining why the Java SE SNMP agent - through its JVM_MANAGEMENT_MIB, doesn't provide access to thread stack traces. That will be an interesting story, nicely linked to this one, but too long for this night.