search the entire class path for those entries until it finds the one the application wants to use
(or until it doesn't find anything and falls back to the system parser). Since reading the JAR
file requires a synchronization lock, all those threads trying to create a parser end up con-
tending for the same lock, which is greatly hampering the application's throughput. (This is
why Chapter 10 recommends setting the -Djavax.xml.parsers.SAXParserFactory prop-
erty to avoid those lookups.)
The larger point here is that a lot of blocked threads is a problem affecting performance.
Whatever the cause of the blocking is, changes need to be made to the configuration or ap-
plication to avoid it.
What about the threads that are waiting for notification? Those threads are waiting for
something else to happen. Often they are in a pool waiting for notification that a task is ready
(e.g., the getTask() method in the output above is waiting for a request). System threads are
doing things like RMI distributed GC, or JMX monitoring—they appear in the jstack out-
put as threads that have only JDK classes in their stack. These conditions do not necessarily
indicate a performance problem; it is normal for them to be waiting for a notification.
Another problem creeps up in the threads waiting for I/O read: these are doing a blocking I/O
call (usually the socketRead0() method). This is also hampering throughput: the thread is
waiting for a backend resource to answer its request. That's the time to start looking into the
performance of the database or other backend resource.
1. Basic visibility into the threads of a system provides an overview of the number
of threads running.
2. For performance analysis, the important facet of thread visibility is when threads
are blocked on a resource or on I/O.
3. Java Flight Recorder provides an easy way to examine the events that caused a
thread to block.
4. jstack provides some level of visibility into the resources threads are blocked on.