设计模式之单例

  1. What is it?
    单例也就是单实例,也就是JVM中只存在一个某类对象,且对外提供一个获取该对象的方法。

  2. Where you can use it?
    单例使用场景众多,如日志记录对象、JDBC驱动对象 、缓存对象、线程池对象等。在JDK的核心类库中, java.lang.Runtime, java.awt.Desktop等为单例对象,并且 AbstractFactory, Builder, Prototype, Facade等设计模式中也使用单例对象(使用单例模式的思想,也就是融会贯通)。

  3. How to implement it?

    • private constructor method

      • 禁止外部创建对象
    • private static this class instance variable

      • 存储该类唯一的对象
    • public method to get this class instance

      • 提供给外部获取该单例对象的方法
  4. Code Demo

  • Eager Initialization
    • Class加载时对象已经创建,缺点是无论Client是否使用,对象已经创建
    • 无异常处理
        public class EagerInitializedSingleton {
            private EagerInitializedSingleton() {
            }
        
            private static final EagerInitializedSingleton instance = new EagerInitializedSingleton();
        
            public static EagerInitializedSingleton getInstance() {
                return instance;
            }
        }
  • Static block initialization
    • 增加异常处理
        public class StaticBlockSingleton {
            private StaticBlockSingleton() {
        
            }
        
            private static StaticBlockSingleton instance;
        
            static {
                try {
                    instance = new StaticBlockSingleton();
                } catch (Exception e) {
                    throw new RuntimeException("exception occured in careating singleton instance.");
                }
            }
        
            public static StaticBlockSingleton getInstance() {
                return instance;
            }
        }

  • Lazy Initialization
    • 优点是Client使用时才创建实例
    • 缺点是线程不安全
        public class LazyInitializedSingletonLazyInitializedSingleton {
            private LazyInitializedSingletonLazyInitializedSingleton() {
            }
        
            private static LazyInitializedSingletonLazyInitializedSingleton instance;
        
            public static LazyInitializedSingletonLazyInitializedSingleton getInstance() {
                if (null == instance) {
                    instance = new LazyInitializedSingletonLazyInitializedSingleton();
                }
                return instance;
            }
        }

  • Thread Safe Sigleton
    • Client使用时创建
    • 线程安全
    public class ThreadSafeSingleton {
        private ThreadSafeSingleton() {
    
        }
    
        private static ThreadSafeSingleton instance;
    
        public synchronized static ThreadSafeSingleton getInstance() {
            if (null == instance) {
                instance = new ThreadSafeSingleton();
            }
            return instance;
        }
    }

  • 双锁校验Thread Safe Singleton
    • 只有第一次创建时使用锁
        public static  ThreadSafeSingleton getInstanceUsingDoubleLocking(){
        if (null == instance){
            synchronized (ThreadSafeSingleton.class){
                if (null == instance){
                    instance = new ThreadSafeSingleton();
                }
            }
        }
        return instance;
    }

  • Bill Pugh Singleton Implementation
    • 使用静态内部类,无需同步锁
    • 线程安全
        public class BillPughSingleton {
            private BillPughSingleton() {
            }
        
            private static class SingletonHelper {
                private static final BillPughSingleton INSTANCE = new BillPughSingleton();
            }
        
            public static BillPughSingleton getInstance() {
                return SingletonHelper.INSTANCE;
            }
        }

  • Using Reflection to destroy Singleton Pattern

    • 通过反射可以破坏单例,创建新对象
        public class ReflectionSingletonTest {
            public static void main(String[] args) {
                EagerInitializedSingleton instanceOne = EagerInitializedSingleton.getInstance();
                EagerInitializedSingleton instanceTwo = null;
                try {
                    Constructor[] constructors = EagerInitializedSingleton.class.getDeclaredConstructors();
                    for (Constructor construtor : constructors) {
                        construtor.setAccessible(true);
                        instanceTwo = (EagerInitializedSingleton) construtor.newInstance();
                    }
        
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(instanceOne.hashCode());
                System.out.println(instanceTwo.hashCode());
        
            }
        }

  • Enum Singleton
    • 不灵活
    • 不支持懒加载
    • 解决反射破坏单例的问题
        public enum EnumSingleton {
            INSTANCE;
        
            public void doSomething() {
        
            }
        }
  • Serialization and Singleton
    • 反序列化时获取的是新对象
    • instanceOne hashCode = 17030099
    • instanceTwo hashCode = 3615232
        public class SerializedSingleton implements Serializable {
            private static final long serialVersionUID = -4535403786288899650L;
        
            private SerializedSingleton() {
            }
        
            private static class SingletonHelper {
                private static final SerializedSingleton INSTANCE = new SerializedSingleton();
            }
        
            public static SerializedSingleton getInstance() {
                return SingletonHelper.INSTANCE;
            }
        }

        public class SingletonSerializedTest {
            public static void main(String[] args) {
                SerializedSingleton instanceOne = SerializedSingleton.getInstance();
        
                try {
                    ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
                    out.writeObject(instanceOne);
        
                    ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
                    SerializedSingleton instanceTwo = (SerializedSingleton) in.readObject();
        
                    System.out.println("instanceOne hashCode = " + instanceOne.hashCode());
                    System.out.println("instanceTwo hashCode = " + instanceTwo.hashCode());
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }

  • 序列化破坏单例问题解决方法
    • 增加方法readResolve(反序列化时会调用)
    • 反序列化时读取的是单例对象不会重新创建新对象
    • instanceOne hashCode = 17030099
    • instanceTwo hashCode = 17030099
        public class SerializedSingleton implements Serializable {
            private static final long serialVersionUID = -4535403786288899650L;
        
            private SerializedSingleton() {
            }
        
            private static class SingletonHelper {
                private static final SerializedSingleton INSTANCE = new SerializedSingleton();
            }
        
            public static SerializedSingleton getInstance() {
                return SingletonHelper.INSTANCE;
            }
        
            protected Object readResolve(){
               return getInstance();
            }
        }
 

你可能感兴趣的:(设计模式之单例)