Twitter

Thursday, April 28, 2011

A peek into JDK7 - Java Phaser: Taking concurrency to the next level

Some days ago there was a discussion with one of my colleague regarding synchronization points between several Java threads. Of course there are CountDownLatch and CyclicBarrier for solving this kind of problems. But even with them we need to know how may threads are we going to start before hand. Because both  CountDownLatch and CyclicBarrier expects the number of parties to be synchronized as the constructor argument.

new CountDownLatch(count);
new CyclicBarrier(parties);

Then I came across Phaser. In case of Phaser you don't need to give the number of parties as an constructor argument. 

new Phaser();

It is one of the concurrency features coming in Java 7. It is designed in such a way that a thread that needs to be in sync with other threads can register() themselves. Like a CyclicBarrier a Phaser can be reused (during several phases of the task). For this use arriveAndAwaitAdvance(), i.e after completing each phase you arrive and wait for all the other threads and once they all reach you advance (move) to the next phase.

In this example code you see 3 threads being started. Once a task begins the thread will register itself with the Phaser. After completing each phase of the task each thread will tell the Phaser that it has completed a certain phase by calling  arrive() and then wait for the others with awaitAdvance(). And at any phase one party can ask the Phaser for the number of parties those have not yet arrived be calling getUnarrivedParties().

@Override
  public void run() {
   
   _phaser.register(); // register on the fly

   // First phase
   doSomeWork();

   int arr1 = _phaser.arrive(); // let the phaser know that you have arrived this point of the task
   int unarrivedParties1 = _phaser.getUnarrivedParties(); // ask the phaser how many parties are not yet here
   
   if (_phaser.getPhase() == arr1) {
    System.out.println(_taskId + " completed phase " + arr1 + " and waiting arraival of " + 
         unarrivedParties1 + " threads so that it can enter phase " + (arr1 + 1));
   }
   else {
    System.out.println(_taskId + " completed phase " + (arr1) + 
         " (the last one to reach) and now all tasks will proceed to phase " + (arr1 + 1));
   }
   
   _phaser.awaitAdvance(arr1); // be in sync with other threads

   
   
   // Second phase
   doSomeWork();

   int arr2 = _phaser.arrive(); // let the phaser know that you have arrived this point of the task
   int unarrivedParties2 = _phaser.getUnarrivedParties(); // ask the phaser how many parties are not yet here

   if (_phaser.getPhase() == arr2) {
    System.out.println(_taskId + " completed phase " + arr2 + " and waiting arraival of " + 
         unarrivedParties2 + " threads so that it can enter phase " + (arr2 + 1));
   }
   else {
    System.out.println(_taskId + " completed phase " + (arr2) + 
         " (the last one to reach) and now all tasks will proceed to phase " + (arr2 + 1));
   }
   _phaser.awaitAdvance(arr2); // be in sync with other threads

   // and so on ...
   
   // at some point a task could de-register itself from the phaser
   _phaser.arriveAndDeregister(); // de-registered threads is not considered need not be in sync with the other threads any more
   

  }

And this is the output:
Thread_1 completed phase 0 and waiting arraival of 2 threads so that it can enter phase 1
Thread_2 completed phase 0 and waiting arraival of 1 threads so that it can enter phase 1
Thread_0 completed phase 0 (the last one to reach) and now all tasks will proceed to phase 1
Thread_0 completed phase 1 and waiting arraival of 2 threads so that it can enter phase 2
Thread_1 completed phase 1 and waiting arraival of 1 threads so that it can enter phase 2
Thread_2 completed phase 1 (the last one to reach) and now all tasks will proceed to phase 2

Tuesday, April 12, 2011

Monitoring Java thread contention

In multi-threaded Java applications it is possible to see some thread contention due to some design or coding problem. Nevertheless if we can pinpoint the contention then it will be easy to find a way to solve the problem. Here we will see how to identify where the contention is and what the lock behind that contention is.

Using  DTrace's monitor probes we can track the contention. Here you can download the Java source code that I used.

In the code you can see that I am using a plain Java Object as a monitor object (also called as lock object).

Object monitorObject = new Object(); // our intrinsic lock

Inside the run() method of my MyCpuIntensiveTask, a executor thread will obtain this lock object before doing some CPU intensive calculation. By the mean time all the other executor threads will be waiting for the lock. Once the first thread exists the synchronized block one of the waiting thread will be granted the lock and so on....

DTrace has the following monitor related probes.

  •     monitor-contended-enter
  •     monitor-contended-entered
  •     monitor-contended-exit
  •     monitor-wait
  •     monitor-waited
  •     monitor-notify
  •     monitor-notifyAll

The following is the DTrace script (using two of the probes) that I have used to test my Java code.

monitor-contended-enter
{
this->threadid = arg0;
this->monitorid = arg1;
this->monitorclass = (string)copyin(arg2, arg3+1);
printf("Thread %d trying to acquire monitor %d of type %s", this->threadid, this->monitorid, this->monitorclass);
}

monitor-contended-entered
{
this->threadid = arg0;
this->monitorid = arg1;
this->monitorclass = (string)copyin(arg2, arg3+1);
printf("Thread %d acquired monitor %d of type %s", this->threadid, this->monitorid, this->monitorclass);
}

  • monitor-contended-enter - will be fired when a thread is trying to acquire a lock which is already held be another thread.
  • monitor-contended-entered - will be fired when a blocked thread enters successfully after acquiring the lock.
The following is the Java code's output. As you can see Thread-7 wasn't blocked since it was the first one to acquire the lock, whereas the others (8,9,10,11) were blocked for some time.

ram@opensolaris:~$ java -XX:+DTraceMonitorProbes -XX:+ExtendedDTraceProbes ThreadContention
Thread 7 trying to acquire lock.
Thread 7 entered.
Thread 8 trying to acquire lock.
Thread 9 trying to acquire lock.
Thread 10 trying to acquire lock.
Thread 11 trying to acquire lock.
Thread 7 exiting.
Thread 11 entered.
Thread 11 exiting.
Thread 10 entered.
Thread 10 exiting.
Thread 9 entered.
Thread 9 exiting.
Thread 8 entered.
Thread 8 exiting.

Exactly the same information is provided by the DTrace script as well but in a more detailed manner. Here we can see the monitor object to acquire which the threads were contending. 135291856 is the id of the object that the threads were trying to acquire. It is of type java/lang/Object. Ofcourse we can use an Integer or any other Java object as a lock.

ram@opensolaris:~# dtrace -s threadContentionMonitor.d
dtrace: script 'threadContentionMonitor.d' matched 2 probes
CPU     ID                    FUNCTION:NAME
  0   5076 __1cNObjectMonitorFenter6MpnGThread__v_:monitor-contended-enter Thread 8 trying to acquire monitor 135291856 of type java/lang/Object
  0   5076 __1cNObjectMonitorFenter6MpnGThread__v_:monitor-contended-enter Thread 9 trying to acquire monitor 135291856 of type java/lang/Object
  0   5076 __1cNObjectMonitorFenter6MpnGThread__v_:monitor-contended-enter Thread 10 trying to acquire monitor 135291856 of type java/lang/Object
  0   5076 __1cNObjectMonitorFenter6MpnGThread__v_:monitor-contended-enter Thread 11 trying to acquire monitor 135291856 of type java/lang/Object
  0   5077 __1cNObjectMonitorFenter6MpnGThread__v_:monitor-contended-entered Thread 11 acquired monitor 135291856 of type java/lang/Object
  0   5077 __1cNObjectMonitorFenter6MpnGThread__v_:monitor-contended-entered Thread 10 acquired monitor 135291856 of type java/lang/Object
  0   5077 __1cNObjectMonitorFenter6MpnGThread__v_:monitor-contended-entered Thread 9 acquired monitor 135291856 of type java/lang/Object
  0   5077 __1cNObjectMonitorFenter6MpnGThread__v_:monitor-contended-entered Thread 8 acquired monitor 135291856 of type java/lang/Object

Saturday, April 2, 2011

Visualizing Java Concurrency

Have you ever wanted to visualize how a BlockingQueue or an Executor or a CountDownLatch or an AtomicInteger works.

Download the jar from here or here and have fun on watching the animation along with the corresponding code side-by-side.

As a sample here is the screenshot for BlockingQueue.


Sync your files online and across computers with Dropbox. 2GB account is free! http://db.tt/307gDHm

Visualizing FJ (Fork And Join) Framework

Earlier I made a post on the new FJ framework in JDK7 here. By the time there was no tool to visualize how FJ works. Today I came across a link where you can download a jar which helps us to visualize FJ.

You can download the jar file from the original link or here from my Dropbox.

Here is a sample screen shop of the jar demo, which sorts numbers from 1-32.

Have fun.