单例模式的五种写法
1)懒汉式(线程安全)
2)DCL(双重校验锁)
3)饿汉式:多线程安全
4)登记式/静态内部类(按需加载)
public class Singleton {
private Singleton(){}
/**懒汉式
* 缺点:每次通过属性instance得到Singleton的实例,都会试图加上一个同步锁,而加锁是一个非常耗时的操作,在没有必要是应该避免。
* 我们只是在实例没有创建之前需要加锁,以保证只有一个线程创建出实例,而当实例已经创建之后,就不需要执行加锁操作了,
* 所以DCL是懒汉式的改进*/
/*
private static Singleton instance = null;
public static synchronized Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}*/
/**DCL
*只有当instance为null时需要加锁,只有第一次试图创建实例时需要加锁 */
/*private volatile static Singleton instance;
public static Singleton getInstance(){
if (instance == null){
synchronized (Singleton.class){
if (instance == null)
instance = new Singleton();
}
}
return instance;
}*/
/**饿汉式*/
/* private static final Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}*/
/**静态内部类(按需加载)*/
private static class SingleHolder{
private static final Singleton instance = new Singleton();
}
public Singleton getInstance(){
return SingleHolder.instance;
}
}
枚举类:多线程安全,如果涉及到反序列化创建对象时,可以尝试使用枚举方式
public enum Singleton{
INSTANCE;
}
破坏单例模式
1)反射机制
s1和s2是两个对象
如果要抵御这种攻击,要防止构造函数被成功调用两次。需要在构造函数中对实例化次数进行统计,大于一次就抛出异常。
2)序列化
通过对Singleton的序列化与反序列化得到的对象是一个新的对象,这就破坏了Singleton的单例性。因为序列化会通过反射调用无参数的构造方法创建一个新的对象。
防止措施:在Singleton中定义readResolve方法,并在该方法中指定要返回的对象的生成策略,就可以防止单例被破坏。
private Object readResolve() {
return instance;
}