单例模式是在学习Java设计模式过程中接触最多的一个模式。单例模式的写法有好几种形式,虽然形式各异,但目的都是为了保证 一个类仅有一个实例,并提供一个访问它的全局入口(getInstance())。
饿汉式
public class Singleton {
private static Singleton instance = new Singleton();
//构造函数私有化 ,确保外部无法直接实例化
private Singleton() {};
public Singleton getInstance() {
return instance;
}
}
懒汉式(添加了“双检锁”,解决数据同步问题)
public class Singleton {
private static Singleton instance;
private Singleton() {};
//添加“双检锁”。解决数据同步问题
public Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class) {//synchoronized关键字也是可以加到方法上,但是这样效率太低了
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
静态内部类中创建单例类实例
//简单实现
public class Singleton {
private Singleton() {};
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public Singleton getInstance() {
return SingleHolder.INSTANCE;
}
}
上面这种实现单例的方式,同样无法避免通过Java的反射机制调用私有的构造函数创建出第二个单例类的实例。为了避免这个问题,我们可以去修改构造函数,使它在被要求创建第二个实例时抛出异常。
//避免“反射”机制攻击
public class Singleton {
private static boolean isCreated;
// 如果二次调用构造函数就抛出一个异常
private Singleton() {
synchronized(Singleton.class) {
if(isCreated) {
throw new RuntimeException("单例模式被攻击了!");
}else {
isCreated = true;
}
}
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
枚举实现单例
public enum Singleton {
INSTANCE;
}
单元素的枚举类型是目前实现单例模式的最佳实践,即可以防止反射攻击,可以防止序列化破坏单例模式。