How to write a Singleton in proper manner?

后端 未结 13 1097
走了就别回头了
走了就别回头了 2020-12-23 12:03

Today in my interview one interviewer asked me to write a Singleton class. And i gave my answer as

public class Singleton {

    private static Singleton re         


        
相关标签:
13条回答
  • 2020-12-23 12:38

    Latest Standard Solutions:

    • Core java with Managed Beans / CDI

      @ApplicationScoped
      public class MySingleton { ... }
      
    • EJB Lite (JEE6)

      @Singleton
      public class MySingleton { ... }
      

    Prior Recommendation (from 'Effective Java 2'):

    • Use an enum, with a single bogus enumeration constant e.g. INSTANCE. Data fields and methods can be either static or non-static (instance) - the two behave equivalently, since there's only one instance

    • Advantages:

      • Yep, it's a singleton. Impossible to create more than one instance by any mechanism (within any given class loader on any JVM).
      • Singleton initialization is thread safe.
    • Disadvantages (compared with above Standard Solutions):

      • The definition is a little obtuse - the 'enum' outer shell could misdirect inexperienced code maintainers. It's a small hack, not the original intention of enum.
      • The implementation leaks through the abstraction. It violates the Uniform Access Principle
        • It doesn't work via injection - the client must know it is a singleton & code against the precise enum instance
        • The client must use Singleton.INSTANCE.someMethod()
        • The client can't (simply) code against an interface
        • The client's impacted by design changes between singleton to/from multi-instance objects
      • Extends an ancestor class (Enum), preventing inheritance from other classes
      • Serialization & deserialization just transfer the enum constant name without state - good for technically ensuring there's only one instance, but a null operation with regards to data. In the (rare) event one wanted to share/synchronise singleton state across JVMs/class loaders, replication via serialization couldn't be used.
    0 讨论(0)
  • 2020-12-23 12:40

    This singleton implementation is called,

    lazy initialization

    But the problem is this implementation is not a thread-safe one.

    Here, you can find the best thread-safe implementation.

    There are few other popular Singleton implementations as well. One is,

    Eager initialization

    final class EagerIntializedSingleton  {
        private static final EagerIntializedSingleton instance = new EagerIntializedSingleton();
        private EagerIntializedSingleton (){}
        private static EagerIntializedSingleton getInsance() {
            return instance;
        }  
    }
    

    But here, the instance of the singleton class is created at the time of class loading. (This is the default singleton class which is created by the IntelliJ IDE)

    The next popular implementation is,

    Static block initialization

    private static StaticBlockSingleton instance;
    private StaticBlockSingleton(){}
    static {
        try {
             instance = new StaticBlockSingleton();
        catch(Exception e) {
             .............
        }
    }
    

    This implementation is similar to eager initialization, except the instance of the class is created in the static block that provides the option for "exception handling". Both eager initialization and static block initialization creates the instance even before it's being used and that is not the best practice to use.

    0 讨论(0)
  • 2020-12-23 12:41

    It could be because it does not use "double-checked-locking" (as others have said) or it could also be because it is apparently possible to invoke a private constructor using reflection (if the security policy allows it).

    To invoke a constructor with no parameters pass an empty array.

    package org.example;
    
    public class Singleton {
    
        private static final Object LOCK = new Object();
        private static final Singleton SINGLETON = new Singleton();
        private static volatile boolean init = false; // 'volatile' to prevent threads from caching state locally (prevent optimizing) 
    
        private Singleton() {
            synchronized (LOCK) {
                if( init == true) {
                    throw new RuntimeException("This is a singleton class!");
                }
                init=true;
            }
        }
    
        public static Singleton obtainClassInstance() {
            return SINGLETON;
        }
    
    }
    
    
    package org.example;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    public class SimpleSingletonTester {
    
        /**
         * @param args
         * @throws NoSuchMethodException 
         * @throws SecurityException 
         * @throws InvocationTargetException 
         * @throws IllegalAccessException 
         * @throws InstantiationException 
         * @throws IllegalArgumentException 
         */
        public static void main(String[] args) throws SecurityException, NoSuchMethodException, 
        IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException 
        {
    
            Class[] parameterTypes = {};
            Object[] initargs = {};
            Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor(parameterTypes);
            System.out.println( constructor.isAccessible() );
            constructor.setAccessible(true);
            System.out.println( constructor.isAccessible() );
            System.out.println( constructor.newInstance(initargs) );
            System.out.println( constructor.newInstance(initargs) );
    
        }
    
    }
    
    0 讨论(0)
  • 2020-12-23 12:43

    He's probably look for this answer:

    public class Singleton 
    {
       private static Singleton ref;
       static
       {
           ref = new Singleton();
       }
       private Singleton()
       {
       }
       public static Singleton getInstance() 
       {
           return ref;
       }
    }
    

    Notice the static block. This approach is probably heavy since the instance is created upon class loading.

    0 讨论(0)
  • 2020-12-23 12:49

    From What is an efficient way to implement a singleton pattern in Java?

    Use an enum:

     public enum Foo 
     {
       INSTANCE;
     }
    

    Joshua Bloch explained this approach in his book 'Effective Java'

    Also check out The better Java singleton pattern nowadays?

    0 讨论(0)
  • 2020-12-23 12:50

    The first thing which comes to my mind when creating a singleton is enum. I generally use enum to implement singleton:

    enum Singleton {
        INSTANCE;
    }
    

    One benefit you get with using enum is with Serialization.

    With singleton class, you would have to make sure that serialization and deserialization doesn't create a new instance by implementing the readResolve() method, while this is not the case with enum.

    Using class you should create the singleton like this:

    public final class Singleton implements Serializable {
        // For lazy-laoding (if only you want)
        private static class SingletonHolder {
            private static final Singleton INSTANCE = new Singleton();
        }
    
        private Singleton() {
            if (SingletonHolder.INSTANCE != null) {
                // throw Some Exception
            }
        }
    
        public static Singleton getInstance() {
            return SingletonHolder.INSTANCE;
        }
    
        // To avoid deserialization create new instance
        @SuppressWarnings("unused")
        private Singleton readResolve() {
            return SingletonHolder.INSTANCE;
        }
    }
    
    0 讨论(0)
提交回复
热议问题