Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Singleton instantiation

Tags:

java

singleton

Below show is the creation on the singleton object.

public class Map_en_US extends mapTree {

    private static Map_en_US m_instance;

    private Map_en_US() {}

    static{
        m_instance = new Map_en_US();
        m_instance.init();
    }

    public static Map_en_US getInstance(){
        return m_instance;
    }

    @Override
    protected void init() {
        //some code;
    }
}

My question is what is the reason for using a static block for instantiating. i am familiar with below form of instantiation of the singleton.

public static Map_en_US getInstance(){
    if(m_instance==null)
      m_instance = new Map_en_US();
}
like image 730
pushya Avatar asked Aug 19 '11 11:08

pushya


People also ask

Can singleton be instantiated?

The main difference is that the singleton object is instantiated in a closure, allowing for a more complex initialization and configuration of the singleton object. The static property is declared private. The singleton object is accessible through the shared() class method.

What is a singleton instance?

A singleton is a class that allows only a single instance of itself to be created and gives access to that created instance. It contains static variables that can accommodate unique and private instances of itself. It is used in scenarios when a user wants to restrict instantiation of a class to only one object.

What does singleton mean in java?

In Java, Singleton is a design pattern that ensures that a class can only have one object. To create a singleton class, a class must implement the following properties: Create a private constructor of the class to restrict object creation outside of the class.

What is an example of a singleton?

Example. The Singleton pattern ensures that a class has only one instance and provides a global point of access to that instance. It is named after the singleton set, which is defined to be a set containing one element. The office of the President of the United States is a Singleton.


1 Answers

The reason is thread safety.

The form you said you are familiar with has the potential of initializing the singleton a large number of times. Moreover, even after it has been initialized multiple times, future calls to getInstance() by different threads might return different instances! Also, one thread might see a partially-initialized singleton instance! (let's say the constructor connects to a DB and authenticates; one thread might be able to get a reference to the singleton before the authentication happens, even if it is done in the constructor!)

There are some difficulties when dealing with threads:

  1. Concurrency: they have to potential to execute concurrently;

  2. Visibility: modifications to the memory made by one thread might not be visible to other threads;

  3. Reordering: the order in which the code is executed cannot be predicted, which can lead to very strange results.

You should study about these difficulties to understand precisely why those odd behaviors are perfectly legal in the JVM, why they are actually good, and how to protect from them.

The static block is guaranteed, by the JVM, to be executed only once (unless you load and initialize the class using different ClassLoaders, but the details are beyond the scope of this question, I'd say), and by one thread only, and the results of it are guaranteed to be visible to every other thread.

That's why you should initialize the singleton on the static block.

My preferred pattern: thread-safe and lazy

The pattern above will instantiate the singleton on the first time the execution sees a reference to the class Map_en_US (actually, only a reference to the class itself will load it, but might not yet initialize it; for more details, check the reference). Maybe you don't want that. Maybe you want the singleton to be initialized only on the first call to Map_en_US.getInstance() (just as the pattern you said you are familiar with supposedly does).

If that's what you want, you can use the following pattern:

public class Singleton {
  private Singleton() { ... }
  private static class SingletonHolder {
    private static final Singleton instance = new Singleton();
  }
  public static Singleton getInstance() {
    return SingletonHolder.instance;
  }
}

In the code above, the singleton will only be instantiated when the class SingletonHolder is initialized. This will happen only once (unless, as I said before, you are using multiple ClassLoaders), the code will be executed by only one thread, the results will have no visibility problems, and the initialization will occur only on the first reference to SingletonHolder, which happens inside the getInstance() method. This is the pattern I use most often when I need a singleton.

Another patterns...

1. synchronized getInstace()

As discussed in the comments to this answer, there's another way to implement the singleton in a thread safe manner, and which is almost the same as the (broken) one you are familiar with:

public class Singleton {
  private static Singleton instance;
  public static synchronized getInstance() {
    if (instance == null)
      instance = new Singleton();
  }
}

The code above is guaranteed, by the memory model, to be thread safe. The JVM specification states the following (in a more cryptic way): let L be the lock of any object, let T1 and T2 be two threads. The release of L by T1 happens-before the acquisition of L by T2.

This means that every thing that has been done by T1 before releasing the lock will be visible to every other thread after they acquire the same lock.

So, suppose T1 is the first thread that entered the getInstance() method. Until it has finished, no other thread will be able to enter the same method (since it is synchronized). It will see that instance is null, will instantiate a Singleton and store it in the field. It will then release the lock and return the instance.

Then, T2, which was waiting for the lock, will be able to acquire it and enter the method. Since it acquired the same lock that T1 just released, T2 will see that the field instance contains the exact same instance of Singleton created by T1, and will simply return it. What is more, the initialization of the singleton, which has been done by T1, happened before the release of the lock by T1, which happened before the acquisition of the lock by T2, therefore there's no way T2 can see a partially-initialized singleton.

The code above is perfectly correct. The only problem is that the access to the singleton will be serialized. If it happens a lot, it will reduce the scalability of your application. That's why I prefer the SingletonHolder pattern I showed above: access to the singleton will be truly concurrent, without the need for synchronization!

2. Double checked locking (DCL)

Often, people are scared about the cost of lock acquisition. I've read that nowadays it is not that relevant for most applications. The real problem with lock acquisition is that it hurts scalability by serializing access to the synchronized block.

Someone devised an ingenuous way to avoid acquiring a lock, and it has been called double-checked locking. The problem is that most implementations are broken. That is, most implementations are not thread-safe (ie, are as thread-unsafe as the getInstace() method on the original question).

The correct way to implement the DCL is as follows:

public class Singleton {
  private static volatile Singleton instance;
  public static Singleton getInstance() {
    if (instance == null) {
      synchronized {
        if (instance == null) {
          instance = new Singleton();
        }
      }
    }
    return instance;
  }
}

The difference between this correct and an incorrect implementation is the volatile keyword.

To understand why, let T1 and T2 be two threads. Let's first assume that the field is not volatile.

T1 enters the getInstace() method. It's the first one to ever enter it, so the field is null. It then enters the synchronized block, then the second if. It also evaluates to true, so T1 creates a new instance of the singleton and stores it in the field. The lock is then release, and the singleton is returned. For this thread, it is guaranteed that the Singleton is completely initialized.

Now, T2 enters the getInstace() method. It is possible (although not guaranteed) that it will see that instance != null. It will then skip the if block (and so it will never acquire the lock), and will directly return the instance of the Singleton. Due to reordering, it is possible that T2 will not see all the initialization performed by the Singleton in its constructor! Revisiting the db connection singleton example, T2 might see a connected but not yet authenticated singleton!

For more information...

... I'd recommend a brilliant book, Java Concurrency in Practice, and also, the Java Language Specification.

like image 119
Bruno Reis Avatar answered Sep 22 '22 22:09

Bruno Reis