2020-10-25

Java 23种设计模式之单例模式

设计模式是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。

单例模式

单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。

1.单例模式的优点:

  1. 保证内存里只有一个实例,减少了内存的开销。
  2. 避免对资源的多重占用。
  3. 设置全局访问点,可以优化和共享资源的访问。

2.单例的实现:

  1. 懒汉式:线程安全(synchronized)
`class Singleton {
   private static volatile Singleton instance; //保证 instance 在所有线程中同步/内存可见
   private Singleton() {}
   public static synchronized Singleton getInstance(){
      if(instance == null) {
         instance = new Singleton();
      }
      return instance;
   }
}`
  1. 饿汉式:类加载时,对象已经创建,并且是final不可变,因此保证了线程安全
`class Singleton {
    private static final Singleton instance=new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return instance;
    }
}
  1. 双重锁:结合懒汉式和饿汉式的优点,既保证线程安全,又提高了效率。
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关键字
  1. 静态内部类:通过静态内部类的方式实现单例模式是线程安全的,同时静态内部类不会在Singleton类加载时就加载,而是在调用getInstance()方法时才进行加载,达到了懒加载的效果
class Singleton {
	private Singleton(){};
	private static class Instance{
		private static Singleton SINGLETION=new Singleton();
	}
	public static Singleton getInstance(){
		return Instance.SINGLETION;
	}
}
  1. 枚举:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
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();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值