Java tutorial index  Java 5 profiling (introduction)  ThreadMXBean

Search this site:
Threads Database Profiling Regular expressions Random numbers Compression Exceptions C Equivalents in Java

 What do you think of this article? Did it help you? Found a mistake? Feedback and suggestions here

Reading the thread profile data: synchronization issues

So far in this discussion, we've seen how to create a thread that sits polling the JVM for the current stack traces (via a ThreadMXBean) of each thread. From this information, we can build up a map of [code position]->[count] information. What we haven't done so far is actually read the profiling information we've so painstakingly gathered!

We need some form of data synchronization to ensure that we can safely read a current snapshot of the profiling data at a given moment, and similarly that the profiler thread can correctly update the data without fear of exposing any reading thread to corrupt data. There are a few options available:

  • we could hold the data in a ConcurrentHashMap;
  • we could use plain old synchronized around access to the map;
  • we could use one of the more explicit locking mechanisms provided by Java 5.

Using a ConcurrentHashMap could work quite well for us, and would certainly allow the profiler thread to write to the data while a reader thread was iterating over the map. But it's arguably ever so slight overkill: ConcurrentHashMap is essentially designed to improve concurrency when we regularly have multiple concurrent accesses. In our case, accesses to read the data by the reader thread will actually be very rare in comparison to the scores or even hundreds of writes to the map being performed every second by the actual profiler thread.

Plain old synchronized actually isn't such a bad choice in this case. In modern JVMs, synchronized implementations are optimised for uncontended access, and possibly for repeated access by the same thread: in other words, precisely the situation we have with our profiler thread.

In this particular case, I'm actually going to opt for using a more explicit locking mechanism. I'm going to use an AtomicInteger to handle the lock. The only real rationale for doing so is that in this case, we know something about the other thread that could possibly be accessing the data, and so by doing things at a low level, we can guide the VM on what to do when there's contention. With synchronized or even something like ReentrantLock, we rely on the VM's generic implementation deciding to "do the right thing".

On the next page, we'll see how we use an AtomicInteger as a lock to synchronize our data.

Written by Neil Coffey. Copyright © Javamex UK 2008. All rights reserved.