保证一个类只有一个实例,并且提供一个全局访问点
适用于重量级对象,不需要多个实例。比如说:线程池、数据库连接池、缓存、日志、注册表。
经典单例模式实现:
public class LazySingleton { //利用一个静态变量来记录Singleton类的唯一实例 private static LazySingleton uniqueInstance; //将构造器声明为私有,只有LazySingleton内才能调用构造器 private LazySingleton() { } //提供一个get方法获取实例对象 public static LazySingleton getUniqueInstance() { if (uniqueInstance == null) { uniqueInstance = new LazySingleton(); } return uniqueInstance; } }
多线程环境中,上述代码可能会产生多个实例,那么加上synchronized关键字到getInstance()方法中,会怎样呢?
public class LazySingleton {
//利用一个静态变量来记录Singleton类的唯一实例
private static LazySingleton uniqueInstance;
//将构造器声明为私有,只有LazySingleton内才能调用构造器
private LazySingleton() {
}
//提供一个get方法获取实例对象(方法上加上synchronized,防止并发)
public static synchronized LazySingleton getUniqueInstance() {
if (uniqueInstance == null) {
uniqueInstance = new LazySingleton();
}
return uniqueInstance;
}
}
此时,多线程的问题解决了,但是方法同步非常消耗性能,如果对性能有很高要求的话,显然这不是一个很好的做法。
双重检查加锁
public class LazySingleton { //利用一个静态变量来记录Singleton类的唯一实例(加上volatile关键字,防止指令重排) private volatile static LazySingleton uniqueInstance; //将构造器声明为私有,只有LazySingleton内才能调用构造器 private LazySingleton() { } //提供一个get方法获取实例对象 public static LazySingleton getUniqueInstance() { if (uniqueInstance == null) { synchronized (LazySingleton.class) { if (uniqueInstance == null) { uniqueInstance = new LazySingleton(); } } } return uniqueInstance; } }
双重检查加锁,首先判断是否已经创建实例了,才进入同步代码块,只有第一次创建实例才会同步。
同懒汉模式不一样,饿汉模式一开始就会创建一个实例
public class HungrySingleton { //初始化时就创建一个实例 private static HungrySingleton uniqueInstance = new HungrySingleton(); private HungrySingleton() { } public static HungrySingleton getUniqueInstance() { return uniqueInstance; } }
public class StaticInnerClassSingleton { private static class InnerSingleton { private static StaticInnerClassSingleton uniqueSingleton = new StaticInnerClassSingleton(); } public static StaticInnerClassSingleton getUniqueSingleton() { return InnerSingleton.uniqueSingleton; } }
public enum SingletonEnum { INSTANCE; }
原文:https://www.cnblogs.com/legalyuke/p/13715546.html