单例的几种安全实现方法及几个问题

2019-01-31  本文已影响0人  entro

线程安全的可用单例模式的几种实现

1.通过static final 实现的饿汉单例

只要编译器一看到该类就会初始化单例,无法达到 延迟加载的目的。

    class Singleton{
        private static final Singleton instance = new Singleton();

        public static Singleton getInstance() {
            return instance;
        }
    }
2.借助静态内部类、static实现的懒汉单例

外部类的静态成员类与外部类没有绑定关系,只有被调用才会加载,从而实现了懒加载。

    class Singleton{    
        private static class SingletonHolder {
            private static final Singleton SINGLETON = new Singleton();
        }
    
        public static Singleton getInstance() {
           return SingletonHolder.SINGLETON;
        }
    }
    
3.双重校验单例模式

加入volatile防止指令重排导致的未完全实例的异常

class Singleton{
    private volatile static Singleton singleton;
           
    public static Singleton getInstance(){       

        if(singleton == null){                      
            synchronized(Singleton.class){          
                if(singleton == null){              
                    singleton = new Singleton();    
                }
            }
        } 
        
        return singleton;           
    }
}
4.枚举单例

把需要单例功能直接定义到一个单枚举中,此方法是《effectJava》推荐的方法
可以做到懒加载,并防止反射(序列化)、反序列化破坏单例

public enum Singleton{
    SINGLETON;
    
}
注意的地方

出了内部类单例和枚举单例外的几种没有对反射(序列化会通过反射调用无参数的构造方法创建一个新的对象。)、反序列化 进行防护,需要在类的内部加入两种防护

    // 序列化会通过反射调用无参数的构造方法创建一个新的对象。
    Singleton(){// 这里防止反射破坏单例
        if(singleton !=null) {
            throw  new RuntimeException("cannot create another instance!");
        }
    }

    //防止反序列化获取多个对象的漏洞
    //无论是实现Serializable接口,或是Externalizable接口,当从I/O流中读取对象时,readResolve()方法都会被调用到。
    private Object readResolve(){
        return singleton;
    }
问题:
上一篇 下一篇

猜你喜欢

热点阅读