Javaweb---线程(4)

volatile关键字:

作用:保证内存可见性 禁止如下代码编译器进行优化
举个栗子:(一个在读一个在写 修改对线程来说可能没改)
在这里插入图片描述

本来应该是内存快速读取数据到CPU中 在CPU中对数字进行比较
但是编译器感觉线程1这个循环没干啥事 于是就对编译器进行了优化.编译器第一次将数据从内存读取到CPU之后 后续直接在CPU寄存器中读取数据(访问的速度 CPU寄存器>内存>CPU 说白了就是学神 学霸 学渣之间的比较) 所以读取的数据一直是0 根本无法跳出循环 但是flag只是在线程1中没有修改 他在线程2中改变了 线程1只是不知道而已 因此出现了误判
编译器优化必须保证优化前后逻辑等价

如果优化生效 不从内存读取数据 因此内存不可见

将代码进行如下操作 就会禁止编译器进行优化
在这里插入图片描述
在这里插入图片描述
一个在读一个在写的代码改正要加上volatile (解决内存可见性)
一个在写另一个还在写必须加syncronized

## 对象等待集: (程序猿通过一定的手段干预线程调度)
对象等待集产生的原因: 抢占式执行的锅.
wait方法: 当操作条件不成熟就等待
(EG:排队买衣服 轮到我了 营业员小姐姐说:没我的号了让我先出队列等 她去在仓库找找有没有)
notify方法: 条件成熟 通知指定线程来执行
(EG:营业员小姐姐说: 找到我的号了 通知我去前台付款)

wait的工作过程:
1.释放锁
2.等待通知
3.收到通过后 尝试获取锁继续往下执行

代码示例:
在这里插入图片描述
在这里插入图片描述
notify代码示例:
一调用wait就先释放锁!

在这里插入图片描述
为了避免竞态条件问题 (线程1释放锁 线程2获取锁获取成功后发送通知必须得让线程1接收到)
事实上线程1的释放锁和等待通知在wait中是原子的

在这里插入图片描述

可重入锁:
在这里插入图片描述
[注意]sleep和wait对比:
1.sleep和wait都是让线程放弃执行一段时间
2.sleep是让线程阻塞 wait是用于线程通信
3.wait执行的时候先获取锁执行完会释放锁 等唤醒后再次请求获取锁
4.sleep是与锁无瓜的
5.wait是object方法 sleep是Thread静态方法

多线程案例:[重点]

单例模式: 常见的设计模式.
用法: 代码中有些概念不应该存在多个实例 此时应使用单例模式
实现(2个):

饿汉模式
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

懒汉模式:
在这里插入图片描述
两种模式的比较:
1.懒汉模式相比饿汉模式效率更高 因为实例化的对象不一定会用到 懒汉模式就保证了用的时候在new
2.线程安全?(多个线程并发调用getInstance()是否会产生逻辑错误)
饿汉模式线程安全: 多线程同时调用getInstance() 的时候表示多个线程同时读取同一个变量 (多线程同时修改是不安全的)
懒汉模式线程不安全:
在这里插入图片描述
为了保证线程安全 要加锁:
加锁的目的:保证判断为空和new的操作是原子的
在这里插入图片描述
在这里插入图片描述
在上面的代码中如果已经实例化好了 每次调用getInstance()还需要涉及加锁 但此时大可不必 代码中涉及到锁会影响性能
所以只需要在实例化调用之前加锁后面就不必再加了
代码修改如下:
实例化之前的时间线:在这里插入图片描述
实例化之后的时间线:
线程仍然安全并且效率提高了在这里插入图片描述
这个代码虽然已经修改了两次但还是有一点问题:
一个线程在修改(先加锁的线程)一个线程在读取(后加锁的线程)
此时会引发编译器的优化 只有第一次在内存中读后续会在CPU暂存器中读 读取的是原来的空值
再次优化代码:
在这里插入图片描述
为了保证上述懒汉模式的线程安全:
1.加锁 保证线程安全
2.双重if判断 提高程序效率
3.volatile 避免内存可见性引发的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值