Skip to content

Instantly share code, notes, and snippets.

@maxixcom
Forked from Razeeman/Singletons.md
Created September 26, 2021 11:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxixcom/55907125d7faa1e02c47af3369ec9d2e to your computer and use it in GitHub Desktop.
Save maxixcom/55907125d7faa1e02c47af3369ec9d2e to your computer and use it in GitHub Desktop.
Thread safe singleton implementations in java and kotlin.

Java

Not thread safe.

class SimpleSingleton {
    private static SimpleSingleton sInstance;
  
    private SimpleSingleton() {}
  
    public static SimpleSingleton getInstance() {
        if (sInstance == null) {
            sInstance = new SimpleSingleton();
        }
        return sInstance;
    }
}

Thread safe, but not lazy.

class SimpleSingleton {
    private static SimpleSingleton sInstance = new SimpleSingleton();
  
    private SimpleSingleton() {}
  
    public static SimpleSingleton getInstance() {
        return sInstance;
    }
}

Thread safe(?) and lazy.

public class Singleton {
    private static final Object LOCK = new Object();
    private static Singleton sInstance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (sInstance == null) {
            syncronized(LOCK) {
                sInstance = new Singleton();
            }
        }
        return sInstance;
    }
}

Thread safe and lazy, but wasteful.

public class Singleton {
    private static Singleton sInstance;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (sInstance == null) {
            sInstance = new Singleton();
        }
        return sInstance;
    }
}

Thread safe, but lazy at the class initialization not on INSTANCE.

public enum Singleton {
    INSTANCE;   
}

Initialization on Demand Holder.

Thread safe and lazy, but only for static fields.

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

Double-Check Locking.

Thread safe and lazy.

Volatile is necessary, but can cause perfomance problems(?), and doesn't work on JDK4 and lower.

public class Singleton {
    private static volatile Singleton sInstance;

    private Singleton() {}

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

Object level lock vs Class level lock in Java

Stolen from HERE.

Object level lock is mechanism when we want to synchronize a non-static method or non-static code block such that only one thread will be able to execute the code block on given instance of the class. This should always be done to make instance level data thread safe.

public class DemoClass
{
    public synchronized void demoMethod() { ... }
}
public class DemoClass
{
    public void demoMethod() {
        synchronized (this) {
            // Thread safe code.
        }
    }
}
public class DemoClass
{
    private final Object lock = new Object();
    
    public void demoMethod() {
        synchronized (lock) {
            //Thread safe code.
        }
    }
}

Class level lock prevents multiple threads to enter in synchronized block in any of all available instances of the class on runtime. This means if in runtime there are 100 instances of DemoClass, then only one thread will be able to execute demoMethod() in any one of instance at a time, and all other instances will be locked for other threads.

Class level locking should always be done to make static data thread safe. As we know that static keyword associate data of methods to class level, so use locking at static fields or methods to make it on class level.

public class DemoClass
{
    // Method is static.
    public synchronized static void demoMethod(){ ... }
}
public class DemoClass
{
    public void demoMethod()
    {
        synchronized (DemoClass.class) {
            // Thread safe code.
        }
    }
}
public class DemoClass
{
    // Static object.
    private final static Object lock = new Object();
 
    public void demoMethod() {
        synchronized (lock) {
            // Thread safe code.
        }
    }
}

Kotlin Example

class Singleton private constructor() {

    companion object {

        @Volatile private var instance: Singleton? = null

        fun getInstance() =
            instance ?: synchronized(this) {
                instance ?: Singleton().also { instance = it }
            }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment