重点等级::star::star::star::star::star:
单例类只能有一个实例;必须自己创建自己的唯一实例;必须给所有其他对象提供这一实例;
单例可以解决全局使用的类频繁地创建与销毁的问题,以节省系统资源
- 日志类
- 管理数据库连接
- 文件管理
java.lang.Runtime.getRuntime()
饿汉式java.awt.Desktop.getDesktop()
懒汉式,synchronized块
单元素的枚举类型是实现单例的最佳方法。
Joshua Bloch, Effective Java 2nd Edition p.18
A single-element enum type is the best way to implement a singleton
enum since jdk1.5
public enum EnumIvoryTower {
INSTANCE;
// Other methods
}
EnumIvoryTower enumIvoryTower1 = EnumIvoryTower.INSTANCE;
EnumIvoryTower enumIvoryTower2 = EnumIvoryTower.INSTANCE;
assertEquals(enumIvoryTower1, enumIvoryTower2); // true
关键点
- 构造方法私有化
- 变量
_instance
使用volatile
修饰,所有的写(write)都将先行发生于读(read)。
volatile,能保证先行发生关系(happens-before relationship)。
/*
* 单例 - 双重检查锁
* DCL (double-checked locking)
*/
final class Singleton {
private volatile static Singleton _instance;
// 饿汉式,直接初始化,线程安全
// private static Singleton _instance = new Singleton();
private static boolean flag = true;
private Singleton() {
// 构造方法私有化
// 阻击反射攻击,此方法只能调用一次
if (flag) {
flag = false;
} else {
throw new IllegalStateException("Already initialized.");
}
}
/*
* 版本1: 懒汉模式,当多个线程同时访问,发生线程安全问题
*/
public static Singleton getInstance() {
if (_instance == null) {//饿汉式,因为已经初始化无需判断
_instance = new Singleton();
}
return _instance;
}
/*
* 版本2 : 对Singleton进行双重检查锁定的实现。
* 目的是最大程度地减少同步成本并提高性能, 仅通过锁定代码的关键部分,不在方法上使用 synchronized
* 如果我们不对 _instance 使用 volatile,那么这仍然是不安全的,因为另一个线程可以查看Singleton的一半初始化实例。
*/
public static Singleton getInstanceDC() {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null) {
_instance = new Singleton();
}
}
}
return _instance;
}
}
这种实现模式有几个问题
- 可以使用反射调用私有构造方法。
AccessibleObject.setAccessible(true)
。 使用反射创建出来的来个对象指定是不一样的。
如果要抵御这种攻击,可以修改构造方法,让它在被要求创建第二个实例的时候抛出异常。 - 使用序列化前后的两个对象不相等。任何一个
ObjectInputStream.readObject
方法,它都会返回一个新建的实例。
而使用枚举实现单例可以避免以上问题。