1、设计模式总述
- 对于Java语言来说,通常包含有6大设计原则和23种设计模式,这些都是前辈们对于开发思想的结晶。
- 我们学习和理解这些设计原则和设计模式,深入掌握其实现原理和使用场景,能够更好的设计我们的系
统架构。编写出具有高性能、高并发、高可用、高可扩展性和高可维护性的代码。
在Java的常见的23种设计模式中,大体上可以分为创建型模式、结构型模式和行为型模式三大类。如下就来详述单例模式的几种常见写法以及在框架或项目中的正确使用姿势
2、单例模式的常见写法
2.1、饿汉模式:
- 懒汉模式:单例实例在类装载的时候进行创建,是线程安全的
public class HungerSingleton {
private static HungerSingleton instance = new HungerSingleton();
private HungerSingleton(){ }
public static HungerSingleton getInstance(){
return instance;
}
}
2.2、懒汉模式
- 懒汉模式:单例实例在第一次使用的时候进行创建,这个类是线程不安全的
- 如果非要保证获取实例的方法是线程安全的,可以用synchronized修饰 getInstance()方法,但性能不太好,不推荐
public class LazySingleton {
private static LazySingleton lazySingleton = null;
private LazySingleton(){}
// public static synchronized Object getInstance(){
public static Object getInstance(){
if (lazySingleton == null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
2.3、双重检测+同步锁
双重检测+同步锁(懒汉模式)实现单例模式:单例实例在第一次使用时 进行创建,双重检测并不能保证线程安全
public class DclSingleton {
private DclSingleton(){ }
private static DclSingleton instance = null;
// 当执行 instance = new DclSingleton() 来创建实例时,CPU会执行如下指令:
// 1) memory = allocate(),分配对象的内存空间
// 2) ctorInstance(),初始化对象
// 3) instance = memory, 设置instance指向刚刚分配的内存
// 如果是单线程地去创建实例没有什么问题,但在多线程情况下,可能会发生指令重排序,打乱上述的三个步骤
// //如果发生了JVM和CPU优化,发生重排序时,可能会按照下面的顺序执行:
//1.memory = allocate() 分配对象的内存空间
//3.instance = memory 设置instance指向刚分配的内存
//2.ctorInstance() 初始化对象
//假设目前有两个线程A和B同时执行getInstance()方法,A线程执行到instance = new SingletonExample4(); B线程刚执行到第一个 if (instance == null){处,
//如果按照1.3.2的顺序,假设线程A执行到3.instance = memory 设置instance指向刚分配的内存,此时,线程B判断instance已经有值,就会直接return instance;
//而实际上,线程A还未执行2.ctorInstance() 初始化对象,也就是说线程B拿到的instance对象还未进行初始化,这个未初始化的instance对象一旦被线程B使用,就会出现问题(即线程B无法获取到完整的实例对象)
public static DclSingleton getInstance(){
if (instance == null){
synchronized (DclSingleton.class){
if (instance == null){
instance = new DclSingleton();
}
}
}
return instance;
}
}
2.4、volatile+双重检测同步锁
- 基于前面在多线程环境下可能存在的指令重排问题,可以使用volatile来修饰实例,即volatile + 双重检测机制(懒汉) 来禁止指令重排
public class DclVolatileSingleton {
// 单例模式, volatile + 双重检测机制 来禁止指令重排
private volatile static DclVolatileSingleton instance = null;
private DclVolatileSingleton(){ }
public static DclVolatileSingleton getInstance(){
if (instance == null){
synchronized (DclVolatileSingleton.class){
if (instance == null){
instance = new DclVolatileSingleton();
}
}
}
return instance;
}
}
2.5、静态代码块实现单例
- 使用静态代码块,使其单例实例在类装载的时候进行创建,以此来保证线程安全
// 饿汉模式,单例对象在类装载的时候进行创建,以此可以保证线程安全
public class StaticSingleton {
private static StaticSingleton instance = null;
private StaticSingleton(){ }
static {
instance = new StaticSingleton();
}
public static StaticSingleton getInstance(){
return instance;
}
}
2.6、枚举实现单例
- 使用枚举类实现单例,该方式也是线程最安全的
public class EnumSingleton {
private EnumSingleton(){ }
public static EnumSingleton getInstance(){
return Singleton.INSTANCE.getInstance();
}
public enum Singleton {
INSTANCE;
private EnumSingleton enumSingleton;
// JVM保证这个方法绝对只调用一次
Singleton() {
enumSingleton = new EnumSingleton();
}
public EnumSingleton getInstance(){
return enumSingleton;
}
}
}