1

So here is the piece of code from EventBus getDefault() static method which returns static instance of EventBus class.

/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
    EventBus instance = defaultInstance;
    if (instance == null) {
        synchronized (EventBus.class) {
            instance = EventBus.defaultInstance;
            if (instance == null) {
                instance = EventBus.defaultInstance = new EventBus();
            }
        }
    }
    return instance;
}

I see that code first checks if instance is null and then in synchronized block again does the same check once more. Why is that.

What if I write it like this.

/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
    EventBus instance = defaultInstance;
    if (instance == null) {
        synchronized (EventBus.class) {
            instance = EventBus.defaultInstance = new EventBus();
        }
    }
    return instance;
}

Is there something wrong with my version? What I am missing here?

madhead
  • 31,729
  • 16
  • 153
  • 201
Amit Bhandari
  • 3,014
  • 6
  • 15
  • 33
  • 4
    This is called [double-checked locking](https://en.m.wikipedia.org/wiki/Double-checked_locking). Try your preferred search engine for more information. – Andy Turner Dec 25 '18 at 11:28
  • It improves performance by avoiding usage of synchronized block, after the singleton has been initialized. Since Java 5, you are better off using volatile. See link above, or this one: https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html – ygor Dec 25 '18 at 12:29
  • Your version is wrong, because it allows for multiple threads to create new instance of EventBus. If you don't mind this, than there is nothing wrong with it. – ygor Dec 25 '18 at 12:33

1 Answers1

1

In your code two threads can get inside of the if statement concurrently when instance is null. Then, one thread enters the synchronized block to initialize instance, while the other is blocked. When the first thread exits the synchronized block, the waiting thread enters and creates another Singleton object. Note that when the second thread enters the synchronized block, it does not check to see if instance is non-null.

So we follow double check initialization, it includes:

  1. Check that the variable is initialized (without obtaining the lock). If it is initialized, return it immediately.
  2. Obtain the lock.
  3. Double-check whether the variable has already been initialized: if another thread acquired the lock first, it may have already done the initialization. If so, return the initialized variable.
  4. Otherwise, initialize and return the variable.

Source

Aditya Narayan Dixit
  • 2,105
  • 11
  • 23