【设计模式】单例模式

单例模式

  • 通过单例模式的方法创建的类在当前进程中只有一个实例对象。
  • 优点:避免频繁创建销毁对象,减轻GC压力。控制全局实例个数:只有一个账号登录。
  • 构造单例模式方式:饿汉式、懒汉式、静态内部类、枚举。

单例模式特点

  • 私有静态变量:作为类的唯一实例。static 成员在没有创建对象时初始化。静态存储区保存引用指向堆中的唯一对象。
  • 私有构造方法:外部类无法通过构造方法创建对象:每次创建对象都需要构造方法,private 限定权限为当前类。
  • 公有静态方法:公开获取实例的唯一方法。通过 类.方法 调用。静态方法访问静态实例对象。
  • 没有公开的set方法,外部类无法调用set方法创建该实例。

饿汉式、懒汉式

  • 创建对象实例的时机不同:饿汉式在类加载时创建对象,懒汉式第一次调用时创建对象。

饿汉式

  • 提前把对象new出来,获取类对象的时候已经存在。
  • 线程安全,在线程访问单例对象之前就已经创建好了。
  • 如果长时间不使用对象,造成资源浪费。
public class Singleton {
    private static Singleton instance = new Singleton();
	
    private Singleton(){}
	
    public static Singleton getInstance(){
        return instance;
    }
}

懒汉式

  • 第一次调用getInstance()时创建对象。
  • 推荐写法:双重校验锁,线程安全。
public class Singleton {
    private volatile static Singleton instance;

    private Singleton() {}

    public  static Singleton getUniqueInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
  • 懒汉式详细分解过程:
1、无锁写法,非线程安全
  • if()条件下可能会创建两个对象。
public class Singleton {  
    private static Singleton instance;  
	
    private Singleton (){}  
  
    public static Singleton getInstance() {  
    	if (instance == null) {  
			instance = new Singleton();  
    	}  
    	return instance;
    }  
}
2、方法加锁,效率太低
  • synchronized 对获取对象的静态方法加锁,每次获取实例时先锁起来,再进行判断。缺点:处理速度慢。
public class Singleton {
    private static Singleton instance = null;
	
    private Singleton(){}
	
    public static synchronized Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}
3、双检,对类加锁,指令重排会出错
  • synchronized 对类加锁,调用方法不加锁,创建对象时加锁,防止多线程创建多实例。
  • instance = new Singleton() 分为开辟空间,初始化,赋值引用三个指令,初始化和赋值指令可能会重排。
  • 指令重排会导致先分配空间赋值再初始化实例,多线程会调用到未初始化的实例。
  • 正常指令顺序:new在堆开辟空间,调用构造方法初始化对象,返回空间地址赋值。
public class Singleton {
    private static Singleton instance = null;
	
    private Singleton(){}
	
    public static Singleton getInstance(){
        if (instance == null){
            synchronized (Singleton.class) {
                if (instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
4、双重校验锁,防止指令重排
  • 对实例添加 volatile,防指指令重排,对象读写到主存,保证线程可见。
public class Singleton {
    private volatile static Singleton instance = null;
	
    private Singleton(){}

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

静态内部类

  • 静态内部类形式的单例可保证线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。
  • 外部类加载时,静态内部类不会立即加载,不占内存。
  • 外部类调用 getInstance() 方法时加载内部类,延迟实例化。
  • 静态内部类利用JVM类的加载机制保证初始化实例对象时线程互斥,线程安全。
  • JVM 保证一个类的()方法在多线程环境中被正确地加锁、同步:多个线程同时去初始化一个类,只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕。
public class Singleton {  
    private Singleton() {} 
	
    public static Singleton getInstance() {  
        return SingletonHolder.instance;  
    }  
	
    private static class SingletonHolder{  
        private static Singleton instance = new Singleton();  
    }  
}  

枚举

public enum Singleton {
	// 定义一个枚举的元素代表实例
	Instance;
}

全静态类

  • 静态类指 static class 修饰的类,静态类一定是静态内部类。
  • 好处:只能通过外部类访问。可以访问外部类的静态属性。
  • 把类中所有属性定义为静态也可以实现单例。
  • 静态类无需实例化即可使用,效率更高,在编译期就完成了静态绑定。
  • 失去面向对象优点:静态方法不能被覆写。但可以继承非 final 的单例类覆写其方法。
  • 静态类适用于简单固定、扩展少的场景。
  • 单例类最主要的优点:单例模式面向对象的特性更强,可以通过继承来实现多态,通过实现接口提供同一接口的不同实现。

参考

https://mp.weixin.qq.com/s?__biz=MzAwNDA2OTM1Ng==&mid=2453150113&idx=1&sn=848b13f729996e6c94478653818df528&scene=21#wechat_redirect

https://blog.csdn.net/jike11231/article/details/106229415

https://blog.csdn.net/mnb65482/article/details/80458571

https://zhuanlan.zhihu.com/p/158928210

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值