Twitter

Showing posts with label thread-safe. Show all posts
Showing posts with label thread-safe. Show all posts

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

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.


Wednesday, March 31, 2010

Java - Cache (frequently used immutable objects) using ConcurrentHashMap.

One of the better way to reduce the impact of garbage collection in any Java application is to reduce the number of newly created objects thereby reducing the amount of garbage produced.

Let us take an example of university admission application. There are two possible titles (Masters and Bachelors) and two possible majors (Computer and Electrical). Let us name the combination of title-and-major as Degree.

Assume that there are thousands of applications submitted every day. Each application will be for the particular combination of the above mentioned Degree. eg. Masters-Computer, Master-Electrical, Bachelor-Computer...

Instead of creating new Degree object for each and every application, we can cache the Degree object. When a particular Degree object is demanded, look for that in the cache. If the cache doesn't contain that, then create it, put it inside the cache and then return it. Since the cache is built using ConcurrentHashMap, it is also thread safe. i.e, Even when there are more than 1 thread running the Degree.valueOf() method for a same set of "title" and "major" strings, ONLY one instance of that particular Degree instance will be constructed and will be used by the threads.

It is clear that we will produce less garbage using caching. But is there is another add-on advantage. It is easier to check whether two Degree objects are equal using reference equality (==) rather that equals() method. ie. we can do Master_Computer==Master_Computer_ANOTHER instead of Master_Computer.equals(Master_Computer_ANOTHER). On my machine == is 9 times faster than equals(). Thereby saving some CPU cycles.

Have a look in the following code on how to build a cache of Objects (Degree) having two String properties. Complete code here.

The main method is the Degree.valueOf() method. Where all the caching is done.

This is just an example. This technique can be used in the telco application servers running with load in terms of 1000s of TPS. Eg. Consider a header/value type of protocol. Instead of creating a particular header 1000s of times per second we can reuse the existing cached header thereby relaxing the CPU and RAM for other useful processing.



......

        Degree MASTER_COMPUTER = Degree.valueOf(MASTER, COMPUTER);
        Degree MASTER_ELECTRICAL = Degree.valueOf(MASTER, ELECTRICAL);
        Degree BACHELOR_COMPUTER = Degree.valueOf(BACHELOR, COMPUTER);
        Degree BACHELOR_ELECTRICAL = Degree.valueOf(BACHELOR, ELECTRICAL);
......

        // we ask the cache for all the possible present values that were created by the above lines.
        // Therefore it returns the existing values; Nothing is created anew.
        System.out.println("\nNo more new constructions for existing entries...");
        Degree MASTER_COMPUTER_1 = Degree.valueOf(MASTER, COMPUTER);

......
        // now ask for something that is not there; cache will create it anew and caches them
        System.out.println("\nNew constructions for non-existing entries...");
        Degree.valueOf("Phd", "Computer");

......    
        // one more advantage of caching : we can compare the reference of two objects instead of checking their equal()ity
        // this is because all requests to Degree.valueOf(MASTER, COMPUTER) always return the very same object
        System.out.println("\nFaster equality check...");

        

Output
New Degree object: Master_Computer
New Degree object: Master_Electrical
New Degree object: Bachelor_Computer
New Degree object: Bachelor_Electrical

No more new constructions for existing entries...
Returning existing instance of Master_Computer

New constructions for non-existing entries...
New Degree object: Phd_Computer

Faster equality check...
Checked with equals().
Checked with reference equality.

Thursday, February 25, 2010

Optimistic CAS Vs Pessimistic synchronized...

As Brian Goetz says, be optimistic and not pessimistic.

Exclusive (synchronized) locking is pessimistic and CAS (compare-and-swap/set) used by AtomicInteger, AtomicLongs etcs are optimistic.

Synchronized (locking) is pessimistic in the sense that we fear that something can go wrong, so lock our stuff and do our work.

CAS is optimistic in the sense that we do some work optimistically and then try to commit our work. But if another guy has did what we did, we re-try to do our work once again.

More here in DeveloperWorks article on Going Atomic.

I wanted to see how CAS outperforms synchronized stuffs and the following code was the outcome.

Here we increment two variables with two different tasks.

The first task PlainIncrementTask increments the plain int of the Holder class using the custom-built synchronized getPlain() and incrementPlain() methods.

The second task AtomicIncrementTask increments the AtomicInteger of the Holder class using the AtomicInteger's incrementAndGet() and get() methods.

You can download the code here.

......
public int incrementAtomic() {
return atomicInteger.incrementAndGet();
}

public int getAtomic() {
return atomicInteger.get();
}

synchronized public int incrementPlain() {
return ++plainInteger;
}

synchronized public int getPlain() {
return plainInteger;
}
.....

And the results (of course) favour AtomicInteger.
mbp $ java Holder
Time taken for PLAIN: 1010 ms
Time taken for ATOMIC: 171 ms
mbp $ java Holder
Time taken for PLAIN: 1045 ms
Time taken for ATOMIC: 169 ms
mbp $ java Holder
Time taken for PLAIN: 1043 ms
Time taken for ATOMIC: 172 ms


So it is always better to use Atomic.* for counters and so on.

And never try to outperform the Java Gurus. ;)