Java Code Geeks
Showing posts with label multi-therading. Show all posts
Showing posts with label multi-therading. Show all posts

Sunday, July 25, 2010

Java Lazy initialization and Double Check Locking

According to the post at the javaworld, the double check locking is broken. I agree with the author, lets see what is double-check-locking idiom.
The below code snippet is usually used to initiate some private member variables lazily.



class SomeClass {
  private Resource resource = null;
   public Resource getResource() {
     if (resource == null)
     resource = new Resource();
     return resource;
   }
}

This is a very common use case, for example most of the time, your code might not need to use resource, so why to initiate this variable if it is too costly. Instead only initiate it when necessary.
This however will not work for multi-threaded applications, as there is a potential race condition. Two threads can see that resource is null and one thread override the resource variable initiated by another thread. Simple solution is to use Synchronized access, like

class SomeClass {
   private Resource resource = null;
   public Resource Synchronized getResource() {
     if (resource == null)
     resource = new Resource();
     return resource;
   }
}

But this is now slow because whether the resource is already being initiated or not, any calls to getReource will synchronized all the threads.
The smarter solution is to use Double Checking idiom something like this -



class SomeClass {
   private volatile Resource resource = null;
   public Resource getResource() {
     if (resource == null) {
     synchronized {
       if (resource == null)
       resource = new Resource();
     }
     }
     return resource;
   }
}

However, because of the Memory model of JAVA specification, the above mentioned code might work in one JVM but might fail at times. If you remove the volatile keyword, it is definitely broken, but even if you keep the volatile keyword, it is not certain that it will work.
So what is the solution ? The author at the javaworld mentions that we should avoid the lazy initialization and the following code -



class SomeClass {
   public static Resource resource = new Resource();
}


But the problem with this code is - whether you need or not, resource will be always initialized.

According to me, better way to use lazy initialization is to use "holder-class" idiom as explained in Effective Java by Joshua Bloch. It works like this -


class SomeClass {
   private static class FieldHolder {
     static final Resource field = new Resource();
   }
   public Resource getResource() {
     return FieldHolder.field;
   }
}


There is no synchronization, so no added cost. When the getResource method will be called for the very first time, it initiates the FieldHolder class for the very first time.

Sunday, October 12, 2008

Java's Synchronization support may lead to read/write performance bottlenecks

In order to support multi-threading applications, Java provides "synchronized" keyword. The problem with Java's basic support of synchronization is that - synchronized keyword locks on the object level. For example, if we mark one method of a class as synchronized, then if one thread is inside this method, no other thread can not run any synchronized code of the same object.
lets take an example of a Cache implementation. Lets say we created one hashtable which is the cahche in our application. It caches some objects which are otherwise to be fetched from the database. In order to save the round-trip, some of the objects are read from the database and are cached inside the hashtable. Now as it is a cache, so there will be more reads than writes. If we use synchronized keyword and use the cache object as synchronized object, all reads and writes to this cache will be serialized. Whereas in reality, multiple reads can happen concurrently and can enhance performance.

For a minute, lets think about a database table, most of the time we read from the table and at times we write into the table. If reads are serialized, the whole application will become slower. So database have concept like "shared lock" and "exclusive lock".

Sometimes it become very obvious in case of Java applications also to adopt to this type of "shared lock" and "exclusive lock". Reads from the cache should hold a shared lock and write to it should hold an exclusive lock.

Since Java's native API does not support this one needs to write his own logic to make sure he is following this shared/exclusvie concepts.

Here comes this book which is very handy - "Concurrent Programming in Java: Design Principals and Practices". The author Doug Lea maintains a site http://gee.cs.oswego.edu/dl/ where he has a package called util.concurrent which can perform lot of such locking. These packages are also getting included in JSR166.