Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Threading : Lazy Initialization vs Static Lazy Initialization

I am going through Java Memory Model video presentation and author is saying it is better to use Static Lazy Initialization compared to Lazy Initialization and I do not clear understand what he wants to say.

I wanted to reach to community and would appreciate if someone can explain difference between Static Lazy Initialization and Lazy Initialization with simple java code example.

Reference: Advanced Programming Topics - Java Memory Model

like image 244
Rachel Avatar asked Sep 14 '11 17:09

Rachel


People also ask

Is lazy initialization thread safe?

Thread-Safe Initialization. By default, Lazy<T> objects are thread-safe.

Is lazy initialization good practice?

Lazy initialization is an excellent performance optimization technique, allowing you to defer the initialization of objects that consume significant CPU and memory resources until you absolutely need them. Take advantage of lazy initialization to improve the performance of your apps.

What is lazy initialisation in Java?

In computer programming, lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed. It is a kind of lazy evaluation that refers specifically to the instantiation of objects or other resources.

What is lazy and eager initialization in Java?

While lazy loading delays the initialization of a resource, eager loading initializes or loads a resource as soon as the code is executed. Eager loading also involves pre-loading related entities referenced by a resource.


3 Answers

I think the author in the presentation refers to the fact that a static field would be initialized only once in a thread-safe way at the first use of the class which contains that field (this is guaranteed by JMM):

class StaticLazyExample1 {

   static Helper helper = new Helper();

   static Helper getHelper() {
      return helper;
   }
}

Here helper field would be initialized upon first usage of StaticLazyExample1 class (i.e. upon constructor or static method call)

There is also Initialization On Demand Holder idiom, which is based on static lazy initialization:

class StaticLazyExample2 {

  private static class LazyHolder {
    public static Helper instance = new Helper();
  }

  public static Helper getHelper() {
    return LazyHolder.instance;
  }
}

Here a Helper instance would be created only upon first call to StaticLazyExample2.getHelper() static method. This code is guaranteed to be thread-safe and correct because of the initialization guarantees for static fields; if a field is set in a static initializer, it is guaranteed to be made visible, correctly, to any thread that accesses that class.

UPDATE

What is the difference between both types of initialization?

The static lazy initialization provides efficient thread safe lazy initialization of the static fields and has zero synchronization overhead. On the other hand if you would like to lazily initialize a non-static field, you should write something like this:

class LazyInitExample1 {

  private Helper instance;

  public synchronized Helper getHelper() {
    if (instance == null) instance == new Helper();
    return instance;
  }
}

Or use Double-Cheked Locking idiom:

class LazyInitExample2 {

    private volatile Helper helper;

    public Helper getHelper() {
      if (helper == null) {
          synchronized (this) {
              if (helper == null) helper = new Helper();
          }
      }
      return helper;
    }
}

Should I mention they both require explicit synchronization and carry additional timing overhead comparing to static lazy initialization?

like image 144
Idolon Avatar answered Oct 24 '22 23:10

Idolon


It is worth noting that the simplest thread safe static lazy initialisation is to use an enum This works because initialisation of static fields is thread safe and classes are lazily loaded anyway.

enum ThreadSafeLazyLoadedSingleton {
    INSTANCE;
}

A class which uses a lazy loaded value is String. The hashCode is only computed the first time it is used. After that the cached hashCode is used.

I don't think you can say that one is better than the other because they are not really interchangeable.

like image 29
Peter Lawrey Avatar answered Oct 24 '22 23:10

Peter Lawrey


Well both implementations can be static so that is the first misunderstanding. The presenter in this video is explaining how you can exploit the thread-safety of class initialization.

Class initialization is inherently thread-safe and if you can have an object initialized on class initialization the object creation too are thread-safe.

Here is an example of a thread-safe statically initialized object

public class MySingletonClass{

   private MySingletonClass(){

   }
   public static MySingletonClass getInstance(){
         return IntiailizationOnDemandClassholder.instance;
   }

   private static class IntiailizationOnDemandClassHolder{
         private static final MySingletonClass instance = new MySingletonClass();

   }

}

What is important to know here, MySingletonClass instance variable will never be created and or initialized until getInstance() is invoked. And again since class initialization is thread-safe the instance variable of IntiailizationOnDemandClassholder will be loaded safely, once and is visible to all threads.

To answer your edit depends on your other type of implementation. If you want to do double-checked-locking your instance variable would need to be volatile. If you do not want DCL then you will need to synchronize access each time to your variable. Here are the two examples:

public class DCLLazySingleton{
  private static volatile DCLLazySingleton instance;

  public static DCLLazySingleton getInstace(){
     if(instance == null){
        synchronized(DCLLazySingleton.class){
            if(instance == null)
                instance=new DCLLazySingleton();
        }
     } 
     return instance;
}

and

public class ThreadSafeLazySingleton{
   private static ThreadSafeLazySingleton instance;

  public static ThreadSafeLazySingleton getInstance(){
     synchronized(ThreadSafeLazySingleton.class){
        if(instance == null){
            instance = new ThreadSafeLazySingleton();
        }
        return instance;
     } 

}

The last example requires a lock acquisition on every request of the instance. The second example requires a volatile-read on each access (may be cheap or not, depends on the CPU).

The first example will always lock once regardless of the CPU. Not only that but each read will be a normal without any need to worry about thread-safety. I personally like the first example I have listed.

like image 27
John Vint Avatar answered Oct 24 '22 21:10

John Vint