懒汉式
public class LazySingleton {
private static LazySingleton singleton;
private LazySingleton() {}
public synchronized LazySingleton getInstance() {
if (singleton == null) {
singleton = new LazySingleton();
}
return singleton;
}
}
饿汉式
public class HungarySingleton {
private static HungarySingleton singleton = new HungarySingleton();
private HungarySingleton(){}
public static HungarySingleton getInstance(){
return singleton;
}
}
双重检查锁
public class DoubleCheckSingleton {
private static volatile DoubleCheckSingleton singleton;
private DoubleCheckSingleton() {}
public static DoubleCheckSingleton getSingleton() {
if (singleton != null) {
return singleton;
} else {
synchronized (DoubleCheckSingleton.class) {
if (singleton == null) {
singleton = new DoubleCheckSingleton();
}
return singleton;
}
}
}
}
使用静态内部类
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton(){}
private static class StaticInnerClass{
private static StaticInnerClassSingleton singleton = new StaticInnerClassSingleton();
}
public StaticInnerClassSingleton getInstance(){
return StaticInnerClass.singleton;
}
}
使用枚举
public class EnumSingleton {
private enum Singleton{
INSTANCE;
EnumSingleton enumSingleton;
Singleton(){
synchronized (this){
enumSingleton = new EnumSingleton();
}
}
}
public EnumSingleton getInstance(){
return Singleton.INSTANCE.enumSingleton;
}
}
各种写法的比较
- 懒汉式:提供了延迟初始化,不使用的时候不会初始化,但是效率不高,每次进来都要加锁,竞争激烈的情况下效率下降严重。
- 饿汉式:借用了JVM classloader机制,这种方式类加载较慢,但在使用的时候速度会比较快。
- 枚举:《effective java》中提的方式,简洁,并且无偿提供了序列化机制,绝对的防止了多次实例化,即时是面对各种序列化或反序列化攻击,推荐使用。
- 静态内部类方式:使用静态内部类的方式,可以借用JVM的classload机制,保证单例,在classloader内部实际上也是通过加锁的方式实现的。
- 双重检查锁:这个在《java并发编程的艺术》中有提及,如果DoubleCheckSingleton没有被volatile修饰,有可能会产生问题,产生问题的根源在于 singleton = new DoubleCheckSingleton(); 这一行。这个可以理解为如下三行伪代码
memory = allocate();//1、分配对象的内存空间
ctorInstance(memory);//2、初始化对象
instance = memory//3、设置instance指向刚刚分配的内存地址