Skip to main content

Java Singletons using enum type (The best method for making Singletons in Java)

Singleton is a class that suppose to have only one instance per JVM. Same instance of the singleton class is reused by multiple threads. Most often we use singletons to represent system configurations, window managers like resource since those instances should be common to all threads and objects within a JVM.

Traditional methods of making singletons

There are several popular methods of making singletons.

Method 1: Singleton with public static final field

public class Singleton {

    public static final Singleton INSTANCE = new Singleton();

    private Singleton() {}

}

Method 2: Singleton with public static factory method

public class Singleton {

    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {}

    public static Singleton getInstance(){
        return INSTANCE;
    }

}

Method 3: Singleton with lazy initialization

public class Singleton {

    private static Singleton INSTANCE = null;

    private Singleton() {}

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

}

Pros and Cons of above methods

All of the above methods enforce the noninstantiability (unable to make instances) using a private constructor. Here we cannot avoid creating the private constructor even though we have nothing to do inside the constructor. Because if we do so, then an implicit parameterless default constructor is created having the same access modifier as the class. For example, if the class is declared public, then the default constructor is public; if the class is declared protected, then the default constructor is protected (Refer oracle docs for more details).

Comparing above methods, first 2 methods don't have a performance difference at all. Method 1 is more clearer and simple. A minor advantage of method 2 is, later you can make the class non singleton without changing the API. You can do it by changing the implementation of the factory method to create a new instance for every call instead of returning the same instance as follows.
public static Singleton getInstance() {
        return new Singleton ();
}
Static fields are initialized at the class loading time. Therefore in both method 1 and 2, singleton instances are created even in a case we don't use them at the run time. This is not a problem as long as the Singleton object is not too big and creating the instance is not much expensive. Method 3 avoids this problem with lazy initialization. In method 3 the instance is created when we access the singleton object for the first time. Fine grained synchronization is used to ensure that no more than 1 objects are created with multiple concurrent threads. 

All of the above methods works fine until you are not doing serialization and deserialization with singleton class. Let's think again how did we achieve the singleton behavior in above methods. It was done by making the constructor private and making inaccessible the constructor to create new instances of the class. But the problem is, actually isn't there any other ways to create an instance of a class other than the constructor? Answer is no. There are some other advance methods.
  1. Serialization and deserialization
  2. Reflection

Problems with serialization and deserialization

In order to serialize above singleton classes we must have to implement those classes with Serializable interface. But doing that is not enough. When deserializing a class new instances are created. Now it doesn't matter the constructor is private or not. Now there can be more than one instance of the same singleton class inside the JVM violateing the singleton property. 
public class SerializeDemo implements Serializable {

    public static void main(String[] args) {
        Singleton singleton = Singleton.INSTANCE;
        singleton.setValue(1);

        // Serialize
        try {
            FileOutputStream fileOut = new FileOutputStream("out.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(singleton);
            out.close();
            fileOut.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        singleton.setValue(2);

        // Deserialize
        Singleton singleton2 = null;
        try {
            FileInputStream fileIn = new FileInputStream("out.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            singleton2 = (Singleton) in.readObject();
            in.close();
            fileIn.close();
        } catch (IOException i) {
            i.printStackTrace();
        } catch (ClassNotFoundException c) {
            System.out.println("singletons.SingletonEnum class not found");
            c.printStackTrace();
        }

        if (singleton == singleton2) {
            System.out.println("Two objects are same");
        } else {
            System.out.println("Two objects are not same");
        }

        System.out.println(singleton.getValue());
        System.out.println(singleton2.getValue());

    }

}
Outputs for the above code is,
Two objects are not same
2
1
Here singleton and singleton2 are two different instances. This violates the singleton property. The solution is, we have to implement the readResolve method which is called when preparing the deserialized object before returning it to the caller. The solution is as follows.
public class Singleton implements Serializable{

    public static final Singleton INSTANCE = new Singleton();

    private Singleton() {
    }

    protected Object readResolve() {
        return INSTANCE;
    }

}
Now the output for above code will be,
Two objects are same
2
2
Now the singleton property is preserved and only one instance of the singleton class exists within the JVM.

Problems with Reflection

An advance user can change the private access modifier of the constructor to anything he want at run time using reflection. If this happens, our only mechanism for noninstantiability breaks. Let's see how this can be done.
public class ReflectionDemo {

    public static void main(String[] args) throws Exception {
        Singleton singleton = Singleton.INSTANCE;

        Constructor constructor = singleton.getClass().getDeclaredConstructor(new Class[0]);
        constructor.setAccessible(true);

        Singleton singleton2 = (Singleton) constructor.newInstance();

        if (singleton == singleton2) {
            System.out.println("Two objects are same");
        } else {
            System.out.println("Two objects are not same");
        }

        singleton.setValue(1);
        singleton2.setValue(2);

        System.out.println(singleton.getValue());
        System.out.println(singleton2.getValue());

    }
}
Output of the above code,
Two objects are not same
1
2
In this way, non accessible private constructor becomes accessible and the whole idea of making the class singleton breaks.

Making Singletons with enum in Java

All of the above problems can be solved very easily by using enum type for making singletons.

Singleton with enum

public enum Singleton {
    INSTANCE;
}
Just above 3 lines makes a singleton without any of the problems discussed above. Since enums are inherently serializable we don't need to implement it with serializable interface. Reflection problem is also not there. Therefore, it is 100% guaranteed that only one instance of the singleton is present within a JVM. Thus, this method is recommended as the best method of making singletons in java.

How to use

public enum SingletonEnum {
    INSTANCE;

    int value;

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}
Main class implementation
public class EnumDemo {

    public static void main(String[] args) {
        SingletonEnum singleton = SingletonEnum.INSTANCE;

        System.out.println(singleton.getValue());
        singleton.setValue(2);
        System.out.println(singleton.getValue());
    }
}
One thing to remember here is when serializing an enum, field variables are not get serialized. For example, if we serialize and deserialize above SingletonEnum class, we will loss the value of the int value field (Refer oracle docs for more details about enum serialization).

All the source codes related to this post can be found at: https://github.com/dulajra/all-about-singletons.git

Comments

Popular posts from this blog

How to play Sinhala subtitles(or any other custom fonts) using MX Player on any Android device

Do you know that you can play sinhala subtitles on your android device using MX player even though the device doesn't support sinhala rendering. Just a simple procedure.

Extend internal memory of any Android device (Root Needed)

Low internal memory is a very common problem between low end android devices. Today most of android devices have both more than enough processing power and RAM size. But the internal memory size is relatively low. Due to low internal memory, we can't install many apps and most of the times sync stops working. Two most popular solutions to low internal memory problem. Link2SD Drawback - Slow down the device vold.fstab method Risk of bricking the phone. Need the appropriate vold.fstab for the device. I'm going to tell you a different method. In this method the SD card is joined to the end of the internal memory. If the internal memory is not enough, then the SD card will be used instead of the internal memory.  I installed NFS Most Wanted and NFS No Limits on a Xpeia E3 Dual after extending the internal memory using this methods. (Xperia E3 Dual has a internal memory of 1.7 GB)

Spring Transaction Management over multiple threads

Spring framework provides a comprehensive API for database transaction management. Spring takes care of all underlying transaction management considerations and provides a consistent programming model for different transaction APIs such as Java Transaction API (JTA), JDBC, Hibernate, Java Persistence API (JPA), and Java Data Objects (JDO). There are 2 main types of transaction management in Spring. They are declarative transaction management which is a high level one and programmatic transaction management which is more advance but flexible. The Spring API works very well with almost all of the transaction management requirements as long as the transaction is on a single thread. The problem rises when we want to manage a transaction across multiple threads. Spring doesn't support transactions over multiple threads out of the box. Spring doesn't explicitly mention that in the documentation. But you will end up with run time errors or unexpected results if you try to do so.