单例模式学习笔记

单例模式:只允许创建一个实例对象
饿汉式 还没使用就已经在类装载过程中完成实例化了

在这里插入图片描述

单例模式用private static final 来修饰类的实例化方法
并用private 来修饰构造方法
给外界暴露用static修饰的getInstance 方法来获取实例对象。

懒汉式 : 要用了才创建

在getInstance方法里 先判断Instance是否为空 再创建 但是要注意多线程时的安全问题 可以用synchronized 修饰getInstance方法 但是锁的范围太大效率不高 有些代码不用锁 所以要细化锁
在这里插入图片描述

尝试在判断是否为空后再加锁,但是不可行因为在一个线程判断为空后,还没往下执行,另一个线程也判断为空 然后往下执行 new一个对象 执行完毕后释放锁 第一个线程依然可以获得锁 然后又new了一个对象 所以不行

在这里插入图片描述

所以要使用Double Check Lock (DCL)双重锁判定 在获得锁后再判断一次Instance是否为空 然后再new对象
在这里插入图片描述

但是还有一个问题 Instance 对象 需不需要volatile修饰
Volatile有两个作用:1.线程间可见 2.禁止指令重排序

线程间可见:
在这里插入图片描述

不加volatile 修饰running时 t.running = false 对于线程t1不可见 m不会打印m end!

Volatile的变量的含义就是 当一个线程改变了这个值后 volatile通知其他线程不能在线程的本地缓存中读这个值 要到内存重新读

禁止指令重排序:
在这里插入图片描述

具体例子 就是 线程一: a=1; x =b; 线程二: b=1; y=a;
一.Start();二.Start()
要是指令重排序就会出现 x0&& y0 的情况

现在回到 在这里插入图片描述

首先线程1来了 new了对象半初始化 m的默认值是0 还未赋值
在这里插入图片描述

New有三条指令第一条是申请内存空间 半初始化 m的默认值是0 第二条是使用构造方法
第三条是建立关联
这时如果发生了指令重排序 那么就会先建立关联指向了半初始化对象 再调用构造方法给对象赋值
在这里插入图片描述

这时要是第二个线程在调用构造方法赋值之前进入 就会使用已经半初始化的对象 但是它的值是0 而不是真正的值 所以会出问题 所以要用volatile来禁止指令重排序
在这里插入图片描述

之前用final修饰Instance现在不用 而是用volatile 是因为 final修饰的变量 不可变 volatile可以

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值