饿汉式
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
恶汉式:不用等待直接返回对象,在类被加载的时候就把Singleton实例给创建出来了。
优点:实现简单,线程安全。
缺点:不需要实例时也加载实例,浪费内存。
懒汉式
public class Singleton{
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null) {instance = new Singleton();}
return instance;
}
}
懒汉式
优点:相比饿汉式,懒汉式显得没那么“饿”,在真正需要的时候再去创建实例
缺点:线程不安全。在并发获取实例的时候,可能会存在构建了多个实例的情况。
懒汉式改进
public class Singleton{
private static Singleton instance = null;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance == null) instance = new Singleton();
return instance;
}
}
懒汉式的线程安全方式,用了synchronized,多线程环境下效率不高。
恶汉变种
public class Singleton{
private static Singleton instance = null;
static{
instance = new Singleton();
}
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
懒汉式,变种,线程安全。
静态内部类【推荐】
public class Singleton{
public static class SingletonHolder{
private final static Singleton instance = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance(){
return SingletonHolder.instance;
}
}
静态内部类,使用枚举方式,线程安全。
通过静态内部类的方式实现单例模式是线程安全的,同时静态内部类不会在Singleton类加载时就加载,而是在调用getInstance()方法时才进行加载,达到了懒加载的效果。
似乎静态内部类看起来已经是最完美的方法了,其实不是,可能还存在反射攻击或者反序列化攻击。
双重校验锁【推荐】
public class Singleton{
private volatile static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null) { //1
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
关于两次判null:
第一次判null,instance为null创建实例,不为null则直接返回;
第二次判null,如果多个线程都运行到1处,而其中一个线程获得锁之后创建了对象,如果这里不判null,那么后来的其他线程会再次创建对象。
为什么要加volatile?
java内存模型中,在创建对象时分3步:1.为对象分配空间;2. 初始化对象;3.返回对象引用。不加volatile时,有可能2和3进行重排序,即先返回对象引用,然后初始化对象,这样多线程下可能出现返回半初始化的对象。
枚举【推荐】
public enum Singleton{
instance;
public void whateverMethod(){}
}