设计模式学习笔记--单例模式

本文深入探讨了单例模式的三种实现方式:饿汉模式、懒汉模式及静态内部类方式。对比了各种方式的优点和不足,并针对反射破坏单例的问题提出了有效解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单例模式学习笔记

去年有整理过一篇单例模式的博客单例模式 整理, 近期在看了学习一些资料后,有了一些新的心得

第一种 : 饿汉模式

class  Singleton2{
	private static  final Singleton2 INSTANCE = new Singleton2();
	private Singleton2(){}
	public static Singleton2 getInstance(){
		return INSTANCE;
	}
}

static 修饰意义:在类加载时就进行初始化单例

final 修饰意义; 防止反射修改单例实例,虽然是私有private修饰词,但是反射机制是可以调用到的,前面博文有讲过Class.forName()和xxx.class,下面会提到如何防止反射破坏单例

饿汉式单例是在类加载的时候就立即初始化,并且创建单例对象。绝对线程安全,在线程还没出现以前就是实例化了,不可能存在访问安全问题。
优点:没有加任何的锁、执行效率比较高,在用户体验上来说,比懒汉式更好。
缺点:类加载的时候就初始化,不管用与不用都占着空间,浪费了内存,有可能占着茅坑不拉屎。
Spring 中 IOC 容器 ApplicationContext 本身就是典型的饿汉式单例。

 第二种: 懒汉模式

//懒汉式单例
//在外部需要使用的时候才进行实例化
public class LazySimpleSingleton {
  private LazySimpleSingleton(){}
  //静态块,公共内存区域
  private static LazySimpleSingleton lazy = null;
  public static LazySimpleSingleton getInstance(){
    if(lazy == null){
       lazy = new LazySimpleSingleton();
     }
     return lazy;
  }
}

这种写法起到了Lazy Loading的效果,但是只能在单线程下使用。是线程不安全

我们可以通过加锁的方式使之线程安全

如下,双重加锁

public class LazyDoubleCheckSingleton {
   private volatile static LazyDoubleCheckSingleton lazy = null;
   private LazyDoubleCheckSingleton(){}
   public static LazyDoubleCheckSingleton getInstance(){
     if(lazy == null){
       synchronized (LazyDoubleCheckSingleton.class){
          if(lazy == null){
             lazy = new LazyDoubleCheckSingleton();
              //1.分配内存给这个对象
              //2.初始化对象
              //3.设置 lazy 指向刚分配的内存地址
          }
       }
     }
     return lazy;
   }
}

这样就没有开始的线程不安全问题

之所以进行两次null的判断,是为了提高效率,毕竟竞争锁也是需要浪费资源的,但是,用到 synchronized 关键字,总归是要上锁,对程序性能还是存在一定影响的。

第三种:静态内部类

//这种形式兼顾饿汉式的内存浪费,也兼顾 synchronized 性能问题
//完美地屏蔽了这两个缺点
public class LazyInnerClassSingleton {
   //默认使用 LazyInnerClassGeneral 的时候,会先初始化内部类
   //如果没使用的话,内部类是不加载的
   private LazyInnerClassSingleton(){}
   //每一个关键字都不是多余的
   //static 是为了使单例的空间共享
   //保证这个方法不会被重写,重载
   public static final LazyInnerClassSingleton getInstance(){
   //在返回结果以前,一定会先加载内部类
      return LazyHolder.LAZY;
   }
   //默认不加载
   private static class LazyHolder{
      private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
   }
}

但是上面这几种创建单例是在不考虑反射的情况下来说,虽然这些构造fang方法都是私有private修饰(如果不是私有修饰构造,那就谈不上什么单例,在外面随便可以调用了),但是反射是可以调用私有方法的,这个在去年的博客中也有提到

 

看看反射破坏单例:

public class LazyInnerClassSingletonTest {
   public static void main(String[] args) {
       try{
		   //很无聊的情况下,进行破坏
		   Class<?> clazz = LazyInnerClassSingleton.class;
		   //通过反射拿到私有的构造方法
		   Constructor c = clazz.getDeclaredConstructor(null);
		   //强制访问
		   c.setAccessible(true);
		   //暴力初始化
		   Object o1 = c.newInstance();
		   //调用了两次构造方法,相当于 new 了两次
		   //犯了原则性问题,
		   Object o2 = c.newInstance();
		   System.out.println(o1 == o2);
			// Object o2 = c.newInstance();
	  }catch (Exception e){
		e.printStackTrace();
	  }
   }
}

如何来防止反射破坏单列呢?

我们可以从构造方法下手,限制创建多个单例

我们队静态内部类进行优化限制,代码如下

//史上最牛 B 的单例模式的实现方式
public class LazyInnerClassSingleton {
	//默认使用 LazyInnerClassGeneral 的时候,会先初始化内部类
	//如果没使用的话,内部类是不加载的
	private LazyInnerClassSingleton(){
	   if(LazyHolder.LAZY != null){
	      throw new RuntimeException("不允许创建多个实例");
	   }
	}
	//每一个关键字都不是多余的
	//static 是为了使单例的空间共享
	//保证这个方法不会被重写,重载
	public static final LazyInnerClassSingleton getInstance(){
	  //在返回结果以前,一定会先加载内部类
	   return LazyHolder.LAZY;
	}
	//默认不加载
	private static class LazyHolder{
	   private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
	}
}

在构造方法进行判断,如果已经实例化过了,在调用构造方法进行实例,抛出异常.

 

内容概要:本文档详细介绍了Analog Devices公司生产的AD8436真均方根-直流(RMS-to-DC)转换器的技术细节及其应用场景。AD8436由三个独立模块构成:轨到轨FET输入放大器、高动态范围均方根计算内核和精密轨到轨输出放大器。该器件不仅体积小巧、功耗低,而且具有广泛的输入电压范围和快速响应特性。文档涵盖了AD8436的工作原理、配置选项、外部组件选择(如电容)、增益调节、单电源供电、电流互感器配置、接地故障检测、三相电源监测等方面的内容。此外,还特别强调了PCB设计注意事项和误差源分析,旨在帮助工程师更好地理解和应用这款高性能的RMS-DC转换器。 适合人群:从事模拟电路设计的专业工程师和技术人员,尤其是那些需要精确测量交流电信号均方根值的应用开发者。 使用场景及目标:①用于工业自动化、医疗设备、电力监控等领域,实现对交流电压或电流的精准测量;②适用于手持式数字万用表及其他便携式仪器仪表,提供高效的单电源解决方案;③在电流互感器配置中,用于检测微小的电流变化,保障电气安全;④应用于三相电力系统监控,优化建立时间和转换精度。 其他说明:为了确保最佳性能,文档推荐使用高质量的电容器件,并给出了详细的PCB布局指导。同时提醒用户关注电介质吸收和泄漏电流等因素对测量准确性的影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值