在实际开发的场景中,部分对象只需要在程序中存在一份即可,因为存在多份没有什么意义。实现单例模式的方式有很多种,通常分为两种懒汉式(使用时在创建对象)和饿汉式(类加载时创建对象)。
public class Singleton1 {
private static final Singleton1 INSTACE = new Singleton1();
private Singleton1(){
}
public static Singleton1 getInstance(){
return INSTACE;
}
}
优点:JVM保证线程安全。
缺点:不管是否有用到,类加载创建就创建实例,浪费资源。
public class Singleton2 {
private static volatile Singleton2 INSTACE;
private Singleton2() {
}
public static Singleton2 getInstance(){
//判定实例实例是否为空,避免频繁的取获取锁
if(INSTACE == null){
synchronized (Singleton2.class){
if(INSTACE == null){
INSTACE = new Singleton2();
}
}
}
return INSTACE;
}
}
volatile修饰原因:在多线程且发生指令重排序的情况下,可能会产生对象未被初始化完全就被返回,其他线程执行该段代码时,发现实例为非空,就会直接使用,可能会导致出现异常。
public class Singleton3 {
/**
* 匿名内部类,外部类被加载,其内部类还不会被加载,等到内部类被使用时才会被加载,也就是调用getInstance方法的时候加载。
*/
private static class Mgr03Holder{
private final static Singleton3 INSTANCE = new Singleton3();
}
public static Singleton3 getInstance(){
return Mgr03Holder.INSTANCE;
}
}
public enum Singleton4 {
INSTANCE;
}
INSTANCE是一个枚举实例,枚举类的成员的实例指向该枚举类对象。
总结:日常开发中通常使用Spring的Bean工厂来帮我们产生单例。