单例模式

单例设计模式

 保证一个类只有一个实例

 懒汉式 (在需要的时候才实例化)

 

 

 

 在单线程环境下 实例只有一个

class SingletonTest{
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        // 都是同一个实例
        System.out.println(singleton1 == singleton2);
    }
    
}
public class Singleton {
    public static  Singleton singleton;
    // 私有化构造方法
    private Singleton(){};
    // 调用该方法的时候才实例化
    public static Singleton getInstance(){
        if(singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }
}

 在多线程的环境下 会创建多个实例

    public static void main(String[] args) {
         new Thread(()->{ 
             Singleton instance = Singleton.getInstance();
             System.out.println(instance);
         }).start();
        new Thread(()->{
            Singleton instance = Singleton.getInstance();
            System.out.println(instance);
        }).start();
    }

 

 

 

// 加锁
  public synchronized static Singleton getInstance(){
        if(singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }

 因为在多线程 并发访问 if(singleton == null) 的时候 会造成线程不安全问题 导致创建2个不同的实例 

 解决方法:

 

 

 如果加 synchronized 程序会有性能的损耗 每次有线程访问 getInstance 方法的时候 都需要进行加锁操作

 优化(双重锁):

 

  public  static Singleton getInstance(){
         // 如果singleton等于空的时候 是不需要加锁的
        if(singleton == null){
            synchronized (Singleton.class){
                singleton = new Singleton();
            }
        }
        return singleton;
    }

 

 

 

 还是会创建两个不同的实例 假如说第一个线程返回实例 第二个线程排队等待 等第一个线程释放锁的时候 第二个线程还是会创建一个新的对象

  //  防止 使用到未初始化的实例和指令重排
    public volatile static  Singleton singleton;
    // 私有化构造方法
    private Singleton(){};
    // 调用该方法的时候才实例化
    public  static Singleton getInstance(){
         // 如果singleton等于空的时候 是不需要加锁的
        if(singleton == null){
            synchronized (Singleton.class){
                // 多加一次判断
                if(singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }

 

 

 只实例化了一个对象

 

静态内部类实现单例

class InnerSingletonTest{
    public static void main(String[] args) {
        InnerSingleton instance1 = InnerSingleton.getInstance();
        InnerSingleton instance2 = InnerSingleton.getInstance();
        System.out.println(instance1 == instance2);
        new Thread(()->{
            InnerSingleton instance = InnerSingleton.getInstance();
            System.out.println(instance);
        }).start();
        new Thread(()->{
            InnerSingleton instance = InnerSingleton.getInstance();
            System.out.println(instance);
        }).start();
    }
}
public class InnerSingleton {
    // 需要的时候 才实例话
    private static class InnerSingletonOne{
        private static InnerSingleton innerSingleton = new InnerSingleton();
    }
    private InnerSingleton(){
        
    }
    public static InnerSingleton getInstance(){
        return InnerSingletonOne.innerSingleton;
    }
}

 

 只有一个实例

 饿汉式

class HungryTest{
    public static void main(String[] args) {
        
    }
}
public class Hungry {
    // 类初始化的时候就创建了
    private static Hungry hungry = new Hungry();
    private Hungry(){};
    public Hungry getHungry(){
        return hungry;
    }

通过反射多例化

class InnerSingletonTest{
    public static void main(String[] args) throws Exception{
        InnerSingleton instance1 = InnerSingleton.getInstance();
        Constructor<InnerSingleton> declaredConstructor = InnerSingleton.class.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        InnerSingleton innerSingleton = declaredConstructor.newInstance();
        System.out.println(innerSingleton == instance1);
    }
}
public class InnerSingleton {
    // 需要的时候 才实例话
    private static class InnerSingletonOne{
        private static InnerSingleton innerSingleton = new InnerSingleton();
    }
    private InnerSingleton(){
        
    }
    public static InnerSingleton getInstance(){
        return InnerSingletonOne.innerSingleton;
    }
}

 

 

  通过反射可以创建多个实例 

  解决方法

  

public class InnerSingleton {
    // 需要的时候 才实例话
    private static class InnerSingletonOne{
        private static InnerSingleton innerSingleton = new InnerSingleton();
    }
    private InnerSingleton(){
        if(InnerSingleton.getInstance() != null){
            throw new RuntimeException("不允许创建多个实例");
        }
    }
    public static InnerSingleton getInstance(){
        return InnerSingletonOne.innerSingleton;
    }
}

 

 

 防止创建多个实例

 使用枚举

class SingletonEnumTest{
    public static void main(String[] args) {
        SingletonEnum singletonEnum1 =  SingletonEnum.INSTANCE;
        SingletonEnum singletonEnum2=  SingletonEnum.INSTANCE;
        System.out.println(singletonEnum1 == singletonEnum2);
    }
    
}
public enum  SingletonEnum {
    INSTANCE;
}

 

 

  反射不支持enum对象的创建

 

class SingletonEnumTest{
    public static void main(String[] args) throws Exception {
        SingletonEnum singletonEnum1 =  SingletonEnum.INSTANCE;
        Constructor<SingletonEnum> instance = SingletonEnum.class.getDeclaredConstructor(String.class,int.class);
        instance.setAccessible(true);
        SingletonEnum singletonEnum = instance.newInstance("INSTANCE",0);
    }
    
}
public enum  SingletonEnum {
    INSTANCE;
}

 

 反序列化对单例造成的破坏

public class InnerSingleton implements Serializable {
    // 需要的时候 才实例话
    private static class InnerSingletonOne{
        private static InnerSingleton innerSingleton = new InnerSingleton();
    }
    private InnerSingleton(){
        if(InnerSingleton.getInstance() != null){
            throw new RuntimeException("不允许创建多个实例");
        }
    }
    public static InnerSingleton getInstance(){
        return InnerSingletonOne.innerSingleton;
    }
}

 

public static void main(String[] args) throws Exception{
        // 将对象序列化 存储到磁盘
        InnerSingleton instance1 = InnerSingleton.getInstance();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream( new FileOutputStream("test"));
        objectOutputStream.writeObject(instance1);
        objectOutputStream.close();
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test")); InnerSingleton instance2 = (InnerSingleton)objectInputStream.readObject(); System.out.println(instance1 == instance2); }

 

 序列化回来 不是同一个对象了

 

 解决方法

 重写readResolve()  方法 记得加版本id

public class InnerSingleton implements Serializable {
    // 需要的时候 才实例话
    private static class InnerSingletonOne{
        private static InnerSingleton innerSingleton = new InnerSingleton();
    }
    private InnerSingleton(){
        if(InnerSingleton.getInstance() != null){
            throw new RuntimeException("不允许创建多个实例");
        }
    }
    public static InnerSingleton getInstance(){
        return InnerSingletonOne.innerSingleton;
    }
    Object readResolve() throws  ObjectStreamException {
        return InnerSingletonOne.innerSingleton;
    }
}

枚举类型支持反序列化机制

序列化枚举类 然后读回来

    public static void main(String[] args) throws Exception {
        SingletonEnum singletonEnum1 =  SingletonEnum.INSTANCE;
        ObjectOutputStream objectOutputStream = new ObjectOutputStream( new FileOutputStream("test1"));
        objectOutputStream.writeObject(singletonEnum1);
        objectOutputStream.close();
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test1"));
        SingletonEnum singletonEnum2 = (SingletonEnum)objectInputStream.readObject();
        System.out.println(singletonEnum1 == singletonEnum2);
    }

 

 

 还是原来的对象

 

posted @ 2020-03-17 17:51  辰梓悦  阅读(113)  评论(0编辑  收藏  举报