vxh.viet
1/11/2018 - 4:15 AM

singleton

Singleton

Singleton in a multi threading environment

SOURCE: StackOverflow, Medium, synchronized keyword, volatile keyword

There are several methods you can use to achieve thread safety with lazy initialization:

Draconian synchronization:

private static YourObject instance;

public static synchronized YourObject getInstance() {
    if (instance == null) {
        instance = new YourObject();
    }
    return instance;
}

This solution requires that every thread be synchronized when in reality only the first few need to be.

Double check synchronization: This also used in Android Architect Blueprint

private volatile static VideoLocalDataSource INSTANCE;
 
public static VideoLocalDataSource getInstance(Context context) {
        if (INSTANCE == null) {
            synchronized (VideoLocalDataSource.class) { // While we were waiting for the lock, 
                if (INSTANCE == null) {                 // another thread may have instantiated the object.
                    INSTANCE = new VideoLocalDataSource(context);
                }
            }
        }
        return INSTANCE;
    }

This solution ensures that only the first few threads that try to acquire your singleton have to go through the process of acquiring the lock.

Initialization on Demand:

private static class InstanceHolder {
    private static final YourObject instance = new YourObject();
}

public static YourObject getInstance() {
    return InstanceHolder.instance;
}

This solution takes advantage of the Java memory model's guarantees about class initialization to ensure thread safety. Each class can only be loaded once, and it will only be loaded when it is needed. That means that the first time getInstance is called, InstanceHolder will be loaded and instance will be created, and since this is controlled by ClassLoaders, no additional synchronization is necessary.

Singleton and Memory leak:

SOURCE: Medium, StackOverflow, StackOverflow

Singleton store Context

public class ContextSingleton {
    private final Context context;
    private static ContextSingleton instance;
    
    public static void getInstance(Context context) {
        if (instance == null) {
            instance = new ContextSingleton(context);
        }
    }
  
    private ContextSingleton(Context context) {
        this.context = context;
    }
}

Because Singleton live throughout the life of the Application, thus an Activity can't be garbage collected if it is keep as a hard reference inside a singleton.

In short. Do not pass any context except app context in your singleton.

public static void init(Context context) {
    if (instance == null) {
        context = context.getApplicationContext();
        instance = new ContextSingleton(context);
    }
}

In details. You can pass activity context if you want, but you need to be aware all the time, you need to clear reference when you stop working with your activity, replace it with another reference, when you start new activity. So it can be huge headache. I highly recommend to not pass any context in your singleton, but, if you still want to do it, please, pass only application context. And if you are 100% sure that you need to pass some ‘local’ context in your singleton (for example, you need to create an mechanism of processing bitmaps in background and displaying them in attached views), think about ‘release context reference’ mechanism. For example, you can use WeakPreference of your context objects, so system will be able to destroy them, during garbage collecting.

What have we learned

Think twice if you want to store context in your singleton. You need to be sure that using the context will be justified. And if you will use some ‘local’ context, provide mechanism for releasing its reference to allow garbage collector mark this object as unused and collect it, otherwise you might face with memory leaks in your app.

Using Enum as Singleton

SOURCE: Medium, StackOverflow

The syntax for this is very simple:

public enum MySingleton {
  INSTANCE;   
  
   // all the methods you want
   public void doSomeStuff()   
}

And invoke it like this:

MySingleton.INSTANCE.doSomeStuff();

This enum approach is immutable, thread safe with no big performance or memory problem.

Singleton consideration

If you need to kill or reset your singleton, in other words, if your singleton's lifetime is shorter than the Application's lifetime, then Singleton is a bad design choice. You should go with a normal Object that is tied to lifecycle of that Acitivity instead.

Minimize the use of Singleton or at least think twice before using them.