Wednesday, September 22, 2010

JavaOne 2010: Visualizing the Java Concurrent API

One of my goals at JavaOne 2010 was to attend some sessions on Java concurrency. I had not been aware of the Java Concurrent Animated project until reading the abstract for this presentation:
This presentation will consists of a series of animations that visualize the functionality of each Java concurrent component. Each animation features buttons that correspond to the methods in that component. Each click of a button creates a thread to calling a method, showing how the threads interact in real time. Each animation is controlled by the actual Java concurrent component it is illustrating, so the animation is not only a visual demonstration, it's also a code example. If you?re still using constructs like Thread.start or wait/notify, you'll want to attend this meeting. The presentation is packaged as a self-executable Java Archive (JAR) file and is available for download. It is a valuable reference.
The abstract looked outstanding, but in the back of my mind I wondered if it was worth going to a presentation on this if I could simply run the advertised self-executable JAR file. It turns out that I was glad that I did attend because there was significant discussion regarding what was graphically being displayed.This was another standing-room-only presentation.

The speakers began the presentation with a brief history of concurrency support in Java. They have worked on this application to serve as an graphical illustrative reference for how the various concurrent structures work.

The specific concurrency structures first discussed were Executors (java.util.concurrent.Executor), which provide the access to thread pools. The "bouncer class of Java" is the Semaphore (java.util.Semaphore). Whereas a lock is reentrant, a Semaphore is not reentrant. It is possible for a Semaphore to be released by a Thread other than the Thread that started the Semaphor.

ReetrantLock (java.util.concurrent.locks.ReentrantLock) is a replacement for synchronized that allows same Thread to reenter. This makes it possible to avoid potential deadlock problem associated with synchronized. The cost is the need to manually unlock it from the same Thread that locked it.

Condition (java.util.concurrent.locks.Condition) is directly related to the Lock (same package!). The Javadoc notation for Condition summarizes its purpose nicely:
Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitraryLock implementations. Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.
Even this Condition still has the possibility of "spurious wakeups."

The ReentrantReadWriteLock (java.util.concurrency.locks.ReentrantReadWriteLock) policy has changed from J2SE 5 to Java SE 6.

CyclicBarrier (java.util.concurrent.CyclicBarrier) and CountDownLatch (java.util.concurrent.CountDownLatch) are familiar concepts for those familiar with working with hardware. The Javadoc describes the CyclicBarrier: "A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point." It also describes an effect described in the presentation: "The CyclicBarrier uses an all-or-none breakage model for failed synchronization attempts: If a thread leaves a barrier point prematurely because of interruption, failure, or timeout, all other threads waiting at that barrier point will also leave abnormally via BrokenBarrierException (or InterruptedException if they too were interrupted at about the same time)."  The Javadoc also provides a nice summary of CountdownLock:
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations of await return immediately. This is a one-shot phenomenon -- the count cannot be reset. If you need a version that resets the count, consider using aCyclicBarrier.
AtomicInteger (java.util.concurrent.atomic.AtomicInteger) is representative of thread-safe access on single variables.  See java.util.concurrent.atomic package description for further details.

The BlockingQueue (java.util.concurrent.BlockingQueue) and Future (java.util.concurrent.Future) [often returned by Executors] were also discussed and demonstrated. Callable is similar to Runnable but returns generic object instead of void.

The java.util.concurrent approach also introduced the ability to set time units explicitly rather than specifying everything in number of milliseconds. This is available via the TimeUnit enum.

Download Java Concurrent Animated at http://sourceforge.net/projects/javaconcurrenta/. Because this executable uses the very concurrent structures it is illustrating, there is no "artificial" rendering of what's happening. This means that even strange or unexpected behaviors can be seen.

On a pretty much unimportant and unrelated note, I was in the same room for two consecutive sessions for the first (and likely only) time during this conference. Both this presentation and the presentation I attended before it (JUnit Kung Fu: Getting More Out of Your Unit Tests) were held in Parc 55's Embarcadero.

No comments: