Singleton best practices - enumeration types for single elements

Posted by senthilnayagam on Wed, 27 Nov 2019 18:11:10 +0100

Next, we will introduce several ways to implement Singleton:

First: double check lock [not recommended]

public class Singleton
{
    private volatile static Singleton instance;

    private Singleton(){};

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

Starved man mode: no security problem, because the object has been created when the class is loaded

class DanLi {
     private DanLi(){} // Privatizing construction methods so that objects cannot be created externally
     private static  DanLi dl = new DanLi(); // Create the object in advance, and the object will be created when the class is loaded
}

Enhanced version:

class DanLi {
     private DanLi(){} // Privatizing construction methods so that objects cannot be created externally
     private static  DanLi dl = new DanLi(); // Create the object in advance, and the object will be created when the class is loaded
     public static DanLi getDanLi(){ // Return object directly when method is called
           return dl;
     }
}

Variant: instantiate INSTANCE during class initialization

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

    public static Singleton getInstance() {
        return instance;
    }
}

Static inner class

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

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

However, there is a common problem in the above methods: they can use AccessibleObject.setAccessible method to call private constructor to create new instance through reflection mechanism

	In general, we can't operate on the private fields of a class, and reflection is no exception. At this time, we can call AccessibleObject.setAccessible(boolean flag) method to allow such access

if (s1 == s2) {
	// Description creates an instance
} else {
	// Note: two different instances are created. If you need to resist this attack, you can throw an exception when you are asked to create a second instance
}

It can be modified as follows:

public class ElvisModified  
{  
    private static boolean flag = false; // Add logo 
 
    private ElvisModified(){  
        synchronized(ElvisModified.class) {  
            if(flag == false)  // Identification mark
            {  
                flag = !flag;  
            }  
            else 
            {  
                throw new RuntimeException("Single mode violated!");  
            }  
        }  
    }  
 
    private  static class SingletonHolder{  
        private static final ElvisModified INSTANCE = new ElvisModified();  
    }  
 
    public static ElvisModified getInstance()  {  
        return SingletonHolder.INSTANCE;  
    }  
 
    public void doSomethingElse()  {  
 
    }  
}

After JDK 1.5, Singleton can be implemented using enumeration types of single elements

public enum Test {
    INSTANCE;

    public void dosomething() {
        System.out.println(this + " is speaking!");
    }

}

// test
public class TestSingleton {

    public static void main(String[] args) {
        Test t1 = Test.INSTANCE;
        t1.dosomething();

        Test t2 = Test.INSTANCE;
        t2.dosomething();

        System.out.println(t1 == t2);
    }

}

// result
INSTANCE is speaking!
INSTANCE is speaking!
true


When Singleton is implemented with a single element enumeration type, an exception is thrown when a new instance is created through the reflection mechanism. Compared with the previous s1 == s2, it can be seen that the enumeration type using single element is similar to the public domain method in function, but it is more concise and provides a serialization mechanism free of charge to absolutely prevent multiple instantiations.

Topics: JDK