单例模式-业务场景和实战优化

230 阅读2分钟

业务场景

单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。I/O与数据库的连接,一般就用单例模式实现de的。Windows里面的Task Manager(任务管理器)也是很典型的单例模式。

来看一个单例模式的例子

public class LanHanSingleton {

    private static LanHanSingleton instance;

    private LanHanSingleton(){

    }

    public static LanHanSingleton getInstance(){
        if (instance == null) {
            instance = new LanHanSingleton();
        }
        return instance;
    }

}
 

以上的例子,就是懒汉式的单例实现。实例在需要用到的时候,才去创建,就比较懒。如果有则返回,没有则新建,需要加下 synchronized关键字,要不然可能存在线性安全问题

单例模式的经典写法

其实单例模式还有有好几种实现方式,如饿汉模式,双重校验锁,静态内部类,枚举等实现方式。

饿汉模式

public class EHanSingleton {

   private static EHanSingleton instance = new EHanSingleton();
   
   private EHanSingleton(){      
   }

   public static EHanSingleton getInstance() {
       return instance;
   }
   
}

饿汉模式,它比较饥饿、比较勤奋,实例在初始化的时候就已经建好了,不管你后面有没有用到,都先新建好实例再说。这个就没有线程安全的问题,但是呢,浪费内存空间呀。

双重校验锁

public class DoubleCheckSingleton {

   private volatile static DoubleCheckSingleton instance;

   private DoubleCheckSingleton() { }
   
   public static DoubleCheckSingleton getInstance(){
       if (instance == null) {
           synchronized (DoubleCheckSingleton.class) {
               if (instance == null) {
                   instance = new DoubleCheckSingleton();
               }
           }
       }
       return instance;
   }
}

双重校验锁实现的单例模式,综合了懒汉式和饿汉式两者的优缺点。以上代码例子中,在synchronized关键字内外都加了一层  if条件判断,这样既保证了线程安全,又比直接上锁提高了执行效率,还节省了内存空间。

静态内部类

public class InnerClassSingleton {

   private static class InnerClassSingletonHolder{
       private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
   }

   private InnerClassSingleton(){}
   
   public static final InnerClassSingleton getInstance(){
       return InnerClassSingletonHolder.INSTANCE;
   }
}

静态内部类的实现方式,效果有点类似双重校验锁。但这种方式只适用于静态域场景,双重校验锁方式可在实例域需要延迟初始化时使用。

枚举

public enum SingletonEnum {

    INSTANCE;
    public SingletonEnum getInstance(){
        return INSTANCE;
    }
}

枚举实现的单例,代码简洁清晰。并且它还自动支持序列化机制,绝对防止多次实例化。