Java 23种设计模式之单例模式
设计模式是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。
单例模式
单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。
1.单例模式的优点:
- 保证内存里只有一个实例,减少了内存的开销。
- 避免对资源的多重占用。
- 设置全局访问点,可以优化和共享资源的访问。
2.单例的实现:
- 懒汉式:线程安全(synchronized)
`class Singleton {
private static volatile Singleton instance; //保证 instance 在所有线程中同步/内存可见
private Singleton() {}
public static synchronized Singleton getInstance(){
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}`
- 饿汉式:类加载时,对象已经创建,并且是final不可变,因此保证了线程安全
`class Singleton {
private static final Singleton instance=new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
- 双重锁:结合懒汉式和饿汉式的优点,既保证线程安全,又提高了效率。
class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
但是该单例模式存在问题,对象创建时,可能发生重排序,即在原本的 instance =new Singleton();这句话创建了一个对象,他可以分解成为如下3行代码:
memory = allocate(); // 1.分配对象的内存空间
ctorInstance(memory); // 2.初始化对象
instance = memory; // 3.设置sInstance指向刚分配的内存地址
重排序为:
memory = allocate(); // 1.分配对象的内存空间
instance = memory; // 2.设置sInstance指向刚分配的内存地址
ctorInstance(memory); // 3.初始化对象
当线程A发生重排序后,instance 获取到内存地址,但此时并没有初始化对象,线程B instance == null 的判断就会成立,获取锁进来,导致单例失败。
解决:可在static Singleton instance; 加上volatile关键字
- 静态内部类:通过静态内部类的方式实现单例模式是线程安全的,同时静态内部类不会在Singleton类加载时就加载,而是在调用getInstance()方法时才进行加载,达到了懒加载的效果
class Singleton {
private Singleton(){};
private static class Instance{
private static Singleton SINGLETION=new Singleton();
}
public static Singleton getInstance(){
return Instance.SINGLETION;
}
}
- 枚举:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
public class Singleton {
//私有化构造函数
private Singleton(){ }
//定义一个静态枚举类
static enum SingletonEnum{
//创建一个枚举对象,该对象天生为单例
INSTANCE;
private Singleton singleton ;
//私有化枚举的构造函数
private SingletonEnum(){
singleton = new Singleton ();
}
public Singleton getInstnce(){
return singleton;
}
}
//对外暴露一个获取Singleton对象的静态方法
public static Singleton getInstance(){
return SingletonEnum.INSTANCE.getInstnce();
}
}