Many of today's Java applications take advantage of the language's ability to support concurrent programming through the use of threads. Multiple threads can potentially share the same data objects, but if the part of your application that controls these threads is designed poorly, you may experience lock contention and correspondingly poorer performance.
In multithreaded applications, for example, if multiple threads access the same resource for reading and writing, thread synchronization problems can occur. If one thread attempts to read from a file whilst another is writing to it, the data may become corrupted. To resolve this problem, the Java language allows a thread to acquire an exclusive lock on objects, preventing any other thread accessing it. Once the thread has finished with the object, it releases it so that other threads can then gain access. However, this mechanism can cause high levels of contention if applications aren't designed with care.
Lock contention occurs when a lock is currently in use and another thread attempts to acquire it by another thread. High levels of contention can occur on locks that are frequently obtained, held for a long time, or both. A highly contended lock (one in which many threads try to gain access) can become a bottleneck in the system, as each running thread will pause its execution until the lock it requires becomes available, limiting application performance.
Guard against locking problems with the JLA
The IBM Lock Analyzer for Java (JLA), a new tool available from alphaWorks that runs on any platform running an IBM-supplied Java SDK or JRE, version 5.0 or above, performs lock analysis on a live application to highlight thread activity and provides insight into how often locks are contended. This view can help with the resolution of lock contention problems and performance issues.
The JLA runs alongside an existing Java application and gathers all of that application's lock information. Each lock is recorded along with details about it, such as how long it is held, whether it contends, and the percentage of the time it blocks threads trying to obtain it. The tool consists of a runtime library that must be loaded at startup with the application you wish to monitor and a front-end graphical user interface that displays the results and performs analysis.
JLA design details
The JLA consists of the following two packages:
- JLAagent. This package, which is platform-dependent and made up of a platform-specific library file and a set of Java classes packaged into a JAR, provides the connection to the Java virtual machine (JVM) to gather the lock statistics on the running application.
- JLAGui. This package, written using Swing, is platform-independent and provides the graphical user interface.
The native library in the JLAagent is written in C and uses the Java Virtual Machine Tool Interface (JVM TI). This interface provides methods to control the execution of applications running inside the JVM. It is through this interface that you can gather thread statistics by making use of functions available in the IBM-released JVM. You can have the JVM load this native library JVM at startup by making a modification to the startup command of the Java application that you wish to analyze. The native library then uses the Java classes packaged with it to create a platform MBean server, which provides the mechanism that allows the JLAGui to connect to the JLAagent.
Once the MBean server has been started, the JLAGui can request lock statistics from the running application by navigating though the server into the native library and then on into the running JVM. Because the JLAagent and JLAGui are connected by MBeans, they do not have to run on the same machine; the JLAGui can connect to the MBean server from anywhere on the network.
Running the JLA
To run the JLA, you first need to configure your application with the JLAagent. Then you can launch the JLAGui to begin monitoring lock performance. If you haven't already done so, download the JLA so that you can follow along.
Configuring an application to use the JLA
There are several versions of the JLAagent, one for each of the platforms supported by an IBM-supplied JRE; you must make sure that you use the JLAagent that corresponds to the platform on which the application you wish to monitor will run. If you use an incorrect version of the JLAagent, the application you're trying to monitor will fail to load and will crash. Each JLAagent package has a name based on the architecture of the JRE that is going to launch it.
Unpack the JLAagent package to a directory on the machine running the application you want to monitor. Add this directory to the Java classpath and the system path. A properties file called JLAtiagent.properties is included in the package; it contains the connection information for launching the MBean server. You can edit this properties file if you wish to modify the default values.
To load the JLAagent with the application to analyze, modify the startup command for the application.
-agentlib:JLAtiagent parameter so that it loads the
native library, add the JLAtiagent.jar added to the
classpath, and specify the location of the JLAtiagent.properties file.
For example, the startup command
java dummy.class would need to be modified as follows:
java -Dcom.sun.management.config.file=JLAtiagent.properties -agentlib:JLAtiagent -cp .;JLAagent.jar dummy.class
If an exception occurs at this point, check to make sure that the correct version of the JLAagent is being used. If everything is OK, the message JLA Client registering MBeanServer will appear on the command line.
At this point, the JLAagent has instructed the VM to start recording lock details even though the JLAGui is not running. This means that when the JLAGui is started, you will be able to view lock statistics for the lifetime of the application.
You can launch the JLAGui with the following command:
java -jar JLAGui.jar
By default, the JLAGui will look for an MBean server running on port 1972 on the localhost; as such, these values need not be specified. But if you want to use different values, either the host or the port value can be modified on the command line, as shown in Table 1:
Table 1. Connection options for JLAGui
|1972||Needs to match the |
|localhost||Can be set to an IP address or valid hostname if you wish to monitor an application running on a remote machine|
When the GUI launches, it will attempt to connect to the agent through the MBean server that is running on the machine and port number you specified in the startup options. If the connection is successful, the screen in Figure 1 will appear:
Figure 1. The initial JLA screen
If the connection is unsuccessful, an error message will appear with the details of the connection the GUI tried to make. Check over the error message to make sure the connections are correct. If necessary, you can close the GUI and restart with amended command-line options. Alternatively, you can check to make sure that the application you want to analyze is running with the native agent attached.
Click the Create Report button to create a snapshot report of the current thread statistics of the application that you're monitoring. You'll see three panels (see Figure 2), which show the Java monitors (those created by the application), the system monitors (those created by the VM), and a summary report page. Any monitor created or used by the application will have an entry in the table and graph. You will see only one entry per monitor even if multiple threads are accessing it. This data is recorded at the monitor level rather than a thread level.
Figure 2. Sample JLA report
The height of each column is based on the value of the slow lock count and is relative to all the columns in the graph. A slow count occurs when the requested monitor is already owned by another thread and the requesting thread is blocked. The color of each bar is based on the value of the %MISS column (see Table 2), with a gradient moving from red (100%) through yellow (50%) and finally on to green (0%). A red bar indicates that the thread blocks every time the monitor is requested, whereas a green bar indicates a thread that never blocks. A quick scan of the graph will show those monitors that are not performing very well.
Table 2 explains the values of the various columns in the report table:
Table 2. Report table legend
|%MISS||Percentage of the total gets (acquires) where the requesting thread was blocked waiting on this monitor.|
|GETS||Total number of successful acquires.|
|NONREC||Total number of nonrecursive acquires. This number includes SLOW gets.|
|SLOW||Total number of nonrecursive acquires that caused the requesting thread to block waiting for the monitor to be freed. This number is included in NONREC.|
|REC||Total number of recursive acquires. A recursive acquire is one where the requesting thread already owns the monitor.|
|TIER2||Total number of Tier 2 (inner spin loop) iterations on platforms that support three-tier spin locking.|
|TIER3||Total number of Tier 3 (outer thread yield loop) iterations on platforms that support three-tier spin locking.|
|%UTIL||Monitor hold time divided by interval time. Hold time accounting must be switched on.|
|AVER_HTM||Average amount of time the monitor was held; recursive acquires are not included because the monitor is already owned when acquired recursively.|
|MONITOR NAME||Monitor name or NULL (blank) if name is not known.|
The JLA in action
A simple example application will help you understand how you can use the JLA to help find areas of lock contention. Imagine an application that consists of two threads,
both trying to access the same object. In this case, the object is a class called
JLAsink that contains two synchronized methods, one for setting a piece of data and one for retrieving it. Both threads are started at the same time and both run in a loop trying to access
JLAsink simultaneously. One thread calls the setter method and the other thread calls the retrieval method.
Figure 3 shows the result of running the JLA against a poorly performing version of this sample application:
Figure 3. Initial snapshot of the JLA
You can see from this screenshot that the
has had 9,161
gets made on it and that the requesting thread was blocked trying to obtain the lock 25 percent of the time. It's clear that this
area of the application is not performing particularly well when it comes to handling threads trying to obtain this lock.
Figure 4 shows the JLA running against a much more efficient version of the sample application:
Figure 4. Snapshot of JLA run against optimized application
You can see that the
JLAsink monitor has had 9,370
gets made on it and not a single one has blocked. This shows that this monitor is behaving optimally
when it comes to handling lock contention. The optimized code is now running faster than the non-optimized code, which you can see by comparing the interval times of each run. The
second run accessed the
JLAsink object more times than the first run and did it in less time.
The development of this tool is being frozen with the current functionality in place. In the future, our team will release a new tool based on the JLA that will provide analysis of live Java applications that goes beyond lock statistics. This tool will take on the functionality of not just the JLA, but also the EVTK and Dump Analyzer tools that you learned about in the earlier articles in this series. This tool is currently in the design stage.
In the next article in the series, you'll return to the Dump Analyzer tool introduced in Part 1 of this series. You'll get a much more in-depth look at the tool's extensibility and learn how to build your own analysis modules for it.
- Java diagnostics, IBM style: Read each installment in this series.
- Threading lightly (Brian Goetz, developerWorks, July - October 2001): This three-part series provides an excellent resource on improving lock contention in an application.
- "More flexible, scalable locking in JDK 5.0" (Brian Goetz, developerWorks, October 2004): Performance expert Brian Goetz offers a look at new locking strategies available in JDK 5.0.
- The developerWorks Java technology zone: Hundreds of articles about every aspect of Java programming.
Get products and technologies
- IBM Support Assistant: Download the ISA and start tuning your Java application today. You can also find out about installing a product plug-in in the ISA.
- IBM Java Runtimes and SDKs: Visit this discussion forum for questions related to the IBM Developer Kits for the Java Platform.
- Java Technology Community: Interact with industry experts as J2EE architects, developers and programmers share their knowledge and experiences on the technology.