单例模式

一.单例模式的优缺点:

单例模式优点:

1.值在内存中只有一个实例,减少内存开销。

2.可以避免对资源的多重占用。

3.设置全局访问点,严格控制访问。

单例模式的缺点:

1.没有接口,不易于扩展

2.如果要扩展只能修改单例对象,违反开闭原则

二.单例模式的实现:

1.饿汉式单例

特点:将实例在静态代码块中实现,类加载时就创建。

缺点:浪费内存空间。

2.懒汉式单例

初始化时不加载,在试用时才加载。

缺点:线程不安全

安全版饿汉式单例:

3.加synchronized关键字 

缺点:锁太重,造成整个系统死锁

4.doublecheck双重锁

看似没有问题,但是single1=new Single1();这一步,不是原子操作,可能存在指令重排,所以就要用volatile。volatile的作用是让指令具有可见性,防止指令重排,所以加上volatile才是真正的doublecheck的实现

那么有没有不使用synchronized的方法呢

5.静态内部类式单例 

利用静态内部类的特性,被调用时才执行生成实例,JVM层面避免了线程安全问题。性能最优,但虽然解决了线程安全问题,但还是会被反射攻击。

利用反射测试一下。返回结果false

那么可以在私有构造器上直接抛异常,强制不能构造

那么问题又来了,序列化的方式也能破坏单例

可以看出序列化输入输出后,实例发生了变化。

稍作修改后,再次测试,发现返回了true。readResolve(return instance;)这个方法起了作用。原来是序列化的时候,会生成一个新的对象,但是在最后返回之前,会检查是否有readResolve这个方法,如果有,则用readResolve()方法返回的值,而原本在序列化过程中生成的新的实例则会被JVM回收。这样就能做到即使被序列化也能保证只返回一个单例。

那么有没有既能保证线程安全,又能不这么麻烦的避免序列化和反射的攻击呢?

6.注册式单例:

利用枚举特性,从JDK层面枚举方式的特性可以不被序列化,而枚举本身就是不可以通过构造创建实例天然的创造了单例的环境,所以不会被反射攻击。

以上为单例模式的学习与总结。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值