单例模式
一、懒汉式
public class Singleton { private volatile static Singleton instance; //声明成 volatile private Singleton (){} public static Singleton getSingleton() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
使用DCL进行锁的双重检查。这里的volatile是亮点:设置内存屏障,防止instance未初始化完就被泄漏出来。(volatile语义不清楚的可能参考:Java并发编程:volatile关键字解析)
二、饿汉式
public class Singleton{ //类加载时就初始化 private static final Singleton instance = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return instance; } }
这种写法简单明了,也线程安全。缺点是它不是一种懒加载模式(lazy initialization),单例会在加载类后一开始就被初始化,即使客户端没有调用 getInstance()方法。
三、静态内部类
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } }
这种写法仍然使用JVM本身机制保证了线程安全问题;由于 SingletonHolder 是私有的,除了 getInstance() 之外没有办法访问它,因此它是懒汉式的;同时读取实例的时候不会进行同步,没有性能缺陷;也不依赖 JDK 版本。
四、总结
一般情况下直接使用饿汉式就好了,如果明确要求要懒加载(lazy initialization)会倾向于使用静态内部类。
4.1 反射
但以上几种方式都无法保证反射出来还是单例。可以通过如下代码验证:
//获得构造器 Constructor con = Singleton.class.getDeclaredConstructor(); //设置为可访问 con.setAccessible(true); //构造两个不同的对象 Singleton singleton1 = (Singleton)con.newInstance(); Singleton singleton2 = (Singleton)con.newInstance(); //验证是否是不同对象 System.out.println(singleton1.equals(singleton2));
网上流传一种方法,可以利用enum!有了enum语法糖,JVM会阻止反射获取枚举类的私有构造方法。
public enum SingletonEnum { INSTANCE; }
4.2 反序列化
反序列化的时候,JVM会根据序列化生成的内容构造新的对象,对于实现了Serializable的单例类来说,这相当于开放了构造方法。为了保证单例类实例的唯一性,我们需要重写resolveObject方法。
resolveObject:反序列化时替换反序列化出的对象,反序列化出来的对象被立即丢弃。此方法在readeObject后调用。readResolve常用来反序列单例类,保证单例类的唯一性。
/** * 在反序列化的时候被调用 * @return 返回根据字节码创建的新对象 * @throws ObjectStreamException */ private Object readResolve()throws ObjectStreamException { return instance; }
参考:
- 作者:水岩
- 出处:http://www.cnblogs.com/waterystone
- 本博客中未标明转载的文章归作者水岩和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如果您觉得本文对您的学习有所帮助,可通过支付宝(左) 或者 微信(右) 来打赏博主,增加博主的写作动力