How to create singleton java

Some ways to create Singleton class in Java

In this article, we will find something out about ways to create Singleton class in Java. Before understanding it, we should read up on this Singleton class.

Table of contents

Eager Initialization Singleton class

 public class Singleton  public static Singleton instance = new Singleton(); private Singleton() <> // do other things // . > 
 public class Singleton  private static Singleton instance = new Singleton(); private Singleton() <> public static Singleton getInstance()  return instance; > // do other things // . > 

These versions have the same performance because modern JVM implementations are almost certain to inline the call to the static factory method and the public final field.

  • Benefits
    • With public final field
      • The declarations make it clear that the class is a singleton: the public static field is final, so it will always contains the same object reference.
      • The public final field version is simpler than the static factory version.
      • It gives us the flexibility to change the our mind about whether the class should be a singleton without changing its API.
      • Applying with generic types.
       Constructor[] constructors = Singleton.class.getDeclaredConstructors(); Constructor constructor = constructors[0]; constructor.setAccessible(true); Singleton tmpSingleton = (Singleton) constructor.newInstance(new Object[0]); 

      To solve this problem, we need to modify the constructor of Singleton with public final field ’s version or the static method — getInstance() of Singleton with static factory ’s version to make it throw an exception if it’s asked to create a second instance.

       public class Singleton  private static boolean isCreatedInstance = false; private static final Singleton instance = new Singleton(); private Singleton()  if (isCreatedInstance)  throw new IllegalStateException(); > else  isCreatedInstance = true; > > public static Singleton getInstance()  return instance; > // do other things // . > 

      Lazy Initialization Singleton class

       public class Singleton  private static final Singleton instance = null; private Singleton() <> public static Singleton getInstance()  if (Objects.isNull(instance))  // Use Objects with Java 7 or later version singleton = new Singleton(); > return singleton; > > 
      • Benefits
        • This way prevents the problem about using singleton with static final field when we do not want to create singleton class’s instance at class loading time.
        • Exception handling will be used in the method.
        • Only use in single-threaded environment.
        • Reflection attacks.

        Thread-safe Singleton class

         public class Singleton  private static final Singleton instance = null; private Singleton() <> public static synchronized Singleton getInstance()  if (Objects.isNull(instance))  // Use Objects with Java 7 or later version singleton = new Singleton(); > return singleton; > > 

        This way will improve the Lazy Initialization Singleton class ’s version when it can use in multi-threaded environment. Let’s have a closer look at Singleton pattern on single core and two cores CPU.

        • Singleton on a Single core CPU
        • Singleton on a two cores CPU
        • Singleton on a multiple cores CPU Let’s suppose we have four cores. T1 thread is running first, then T2 needs to wait for T1 to leave the synchronized method to be able to read instance. And if on our two other cores, we have two other threads, T3 and T4, who also want to read our instance variable, well those threads will have to wait for T2 to leave the getInstance() method. At this point, instance has been created, so all the reads could happen at the same time, but since our getInstance() method is synchronized, no more than one thread can enter it at a given time. So no more than one thread can read instance at the same time, and this is really a performance hit because the more cores we have, the more time we’re going to lose since the reads cannot be made in parallel. Of course, all the reads could be made in parallel in a correct way, but the synchronization of the method does not allow that.
      • Benefits and Drawbacks
        • Benefits
          • Use in multithread environment.
          • It still has the benefits of Lazy Initialization Singleton class ’s version.
        • Drawbacks
          • getInstance() method is synchronized so it causes slow performance as multiple threads can’t access it simultaneously.
      • Double-checking Singleton class

         public class Singleton  private volatile static final Singleton instance; private Singleton() <> public static Singleton getInstance()  if (Objects.isNull(instance))  // Use Objects with Java 7 or later version synchronized (Singleton.class)  if (Objects.isNull(instance))  instance = new Singleton(); > > > return instance; > > 

        When we see about this code, we can find that we still have encountered the performance overhead at the first time, only one thread will be entered into the synchronized block of static class, the remained threads will be waited for some times. After the first moment, the performance for using Singleton class do not affected by the first null checked condition. Note that using volatile keyword for instance variable, it will tell the compiler that always to read / write from the main memory, not use CPU cache or local thread stack.

        • Some possible issues with Double-Checking Singleton
          • Singleton on a Multiple Cores CPU In our Singleton class, we have a private static field called instance of type Singleton. It is just a pointer that will point to our only instance of the Singleton class. But the creation of this object is, in fact, a two step process.
            • Memory Allocation (a)
            • The copy of the pointer that points to the newly allocated memory into the Singleton field, which is called instance. (b)
            • The construction process of the Singleton object. This allocated memory belongs to the Singleton class, it has a certain number of fields, certain number of methods, … (c)

            Between the b step and the c step, we do not know which one is going to be executed first. If the construction process is executed first, then the copy of the pointer, everything will be fine because we cannot observe a non null instance pointer that points to a non fully built piece of memory.

            But if the copy of the pointer occurs first, and that we read this instance field in another thread, then we will have visibility on a portion of memory that has been allocated but is not fully initialized yet, and this weird case could happen in the double-check locking. We do not have the guarantee that this second case will not happen, and if it does then very bad things can happen to our applications because basically what we can do is call methods on an object that is not fully built, that is completely corrupted at this step.

Оцените статью