设计模式---单例模式

目录

1.什么是单例模式

2.单例模式的特点

3.单例模式的四大原则

4.实现单例模式的几种方式

4.1.饿汉式(立即加载)

4.2.懒汉式(延迟加载)

4.3.同步锁(解决线程安全问题)

4.4.双重检查锁(提高同步锁的效率)

4.5.静态内部类

4.6.内部枚举实现(防反射和反序列化)

5.小疑问


本文介绍了五种实现单例模式的方式,有饿汉式,懒汉式,同步锁,双重检查锁,静态内部类,内部枚举类,对于实现过程中的一些小问题在文末。

1.什么是单例模式

单例模式,顾名思义,就是保证单例,确保某个类只有一个实例存在,并且这个实例是这个类自行实例化并且供整个系统使用。例如生活中打印机就是一个很好的单例模式的实现,每台计算机可以有多个打印机,但是只能有一个Pringt Spooler,相当于只能有一个调度中心,他会调度打印工作,防止多个打印工作输出到同一台打印机,确保准确性,一致性。选择单例模式最大的优点就是避免不一致状态,保证全局对象的唯一性

2.单例模式的特点
  • 单例类只能有一个实例;
  • 单例类必须自己创建自己的唯一实例(使用私有构造);
  • 单例类必须给所有其他的对象提供这一实例;
3.单例模式的四大原则
  • 构造私有:单例类中需要显式声明私有的构造方法,供单例类自身创建实例使用同时避免外部调用构造方法创建;
  • 以静态方法或者枚举返回实例:因为单例类创建的对象要供系统使用,所以需要保证程序内部全局可访问,并且静态方法或枚举可以在没有实例对象的情况下被调用;
  • 确保实例只有一个:尤其是在多线程环境下,必须保证实例只有一个;
  • 确保反序列时不会重新构建对象:当一个对象被序列化(即转换成字节流以便存储或传输),然后再反序列化(即从字节流中恢复对象)时,就有可能会重新构建对象,这可能会破坏单例模式的约束,导致多个对象实例的产生。
4.实现单例模式的几种方式
4.1.饿汉式(立即加载)

饿汉式就是在类加载的时候就创建一个静态实例

4.2.懒汉式(延迟加载)

懒汉式就是当调用到单例类中的静态方法时才创建实例,从饿汉跟懒汉两个的名字也大概能知道这两种的区别,一个是“饿汉”,迫不及待,加载的时候就要创建出来,一个是“懒汉”,懒得不想自己动,只有当别人来调用采取创建(赖克包型,夺哈扭哈),但是懒汉式在多线程环境下会出现产生多个实例的情况。

4.3.同步锁(解决线程安全问题)

使用synchonized对方法或代码块加同步锁,解决了多线程环境下单例,但是效率低下

4.4.双重检查锁(提高同步锁的效率)

双重检查锁是对上面那个方法的优化,因为对整个方法加锁效率太低,所以可以只对相关代码块加锁

4.5.静态内部类

静态内部类只有在调用时才会加载,这种方式同时满足Singlrton实例的延迟加载,同时也保证了唯一性,这种方法将singleton的实例化操作放到了一个静态内部类中,在第一次调用getInstance()方法的时候才会加载内部类,同时实现Singleton初始化,这样也能让getInstance线程安全。

4.6.内部枚举实现(防反射和反序列化)

枚举有对于反射的防御机制,可以防止反射和反序列化攻击。

5.小疑问
5.1.为什么还是可以通过new关键字创建实例?

这里有个小的点就是有人可能会好奇,我们在main函数里面通过new关键字还是可以创建出对应实例,即使类的构造函数是私有的。如下:

可以看到singleton2这个实例获得了内存地址,也就是被创建出来了。这是因为这里main函数是这个类中的,他们在同一个类的静态方法中,同一个类中访问私有构造自然也就也就不受访问修饰符的约束。但是当我们在另一个类中试图用new关键字创建实例的时候,就是行不通的,如:

5.2.什么是返序列化攻击?

我们知道,序列化可以将一个单例的实例对象写到磁盘,必然也可以再反序列化读回来,这样会获得一个新的实例。即使构造函数是私有的,反序列化时依然可以通过特殊的途径去创建类的一个新的实例,相当于调用该类的构造函数。别有用心的人就可能利用这点来越过你私有的权限。

5.3.双重检查锁那里为什么需要判断两次,一次不行吗?

答案是否定的,必须要两次判断。原因:双重检查锁就是为了解决多线程下实例不唯一的问题,如果只判断一次,当两个线程A,B同时进入到该方法,两个线程都会进入到同步判断,锁的存在使得他们当中只有一个才能继续往下进入到同步代码块,另一个线程会等待(假设B等待,A先行),如果线程A执行完,就会释放锁,不受synchonized保护,B线程进入到代码块后,因为没有二重判断,会直接创建一个新的实例。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值