volatile作用、优缺点、原理

参数书籍:《Java性能优化权威指南》、《Java并发编程实战》

结论:(先说结论)

  • 线程安全
    • 字段(field、变量、数)层次
    • 语句 (语句包含 字段)层次
  • volatile作用于 变量层次,无法作用 语句层次(加锁等确保)
  • 所以volatile保证不了线程安全

使用情景

  • volatile变量不依赖于 之前状态,不依赖于 其他变量
    • 例如:volatile boolean alreadyEat
    • 一个线程写变量  我吃了 alreadyEat = true。 3、4个线程读  if(alreadyEat)playGame ,
    • volatile的局限性就是 playGame这一串逻辑,不可以再写变量 alreadyEat (否则就是依赖了 alreadyEat == true这个状态)
    • 不适用情景就是  if (isDoorOpen) isDorOpen = false, 这种你要用原子变量 AtomicBoolean isDoorOpen,  if(isDoorOpen.getAndSet(flase))
    • AtomicBoolean这种是CAS compare and swap,是可以硬件级别保证 原子性,而且还不 阻塞线程。 very good

 

大白话(2020/01/30补充):

  • CPU 存储(寄存器、register、高速缓存),RAM(内存、内存条)
  • CPU核心有 运算、存储 两个功能
  1. RAM也有存储,两个存储,就导致了数据不一致
  2. CPU多核心,核心之间、内存之间 也会数据不一致
  • 简单的举例下,正确的以后补充
    • CPU从RAM读取变量 varable1、varable2 保存在 register1、register2
    • 相加 保存在register3
    • register3写回到RAM

volatile作用:

  •  volatile字段值 在内存、CPU寄存器中一致
    • 通过 内存屏障 实现
    • 无论那个CPU寄存器 更改,数据都一致

内存屏的内核实现

#include <linux/kernel.h>
// 插入内存屏障,对硬件无影响
void barrier(void)
// 把 CPU寄存器中的所有修改的数值 写入内存。 
// 可屏蔽编译器优化
// 但对 硬件的指令重排 无效

#include <asm/system.h>
//出入硬件内存屏障,实现平台相关

//保屏障前后 读操作的不乱序
void rmb(void); //(读内存屏障)
//不推荐,推荐用rmb
void read_barrier_depends(void);
//写操作不 乱序
void wmb(void);
//读写操作不乱序
void mb(void);

 

线程安全 条件:

  1. 可见性
    1. 变量层次:数据的更改,对所有的CPU的register都一致(你更改,我能看见)
  2. 原子性
    1. 变量层次:比如 double 变量运算
    2. 代码层次:生产者、消费者问题,if***then***。(volatile保证不了)
  3. 指令重排()
    1. volatie可以阻止,但实际是
    2. 代码变成机器指令,在硬件层次、编译层次 会重新排序 优化。

 

为什么volatile保证不了线程安全

volatile只能作用于 变量层次、无法作用于 语句层次(加锁等确保)

举例:

if(volatile no exist) 

    then new volatile.
  1. if的判断volatile保证当时确实正确,然后线程a可能睡着了,
  2. 线程b也判断不存在,b线程就new了一个。
  3. 然后a线程wake up,据需执行new volatile。

就有了两个volatile的对象,

 

怎样变成线程安全

  • 保证代码层次的 原子性
    • 本例:对 if--》create这个过程加锁
  • 后者 代码层次 本身就原子性

 

实现原理:

    CPU缓存中的volatile字段被一个线程修改后,其他CPU缓存中的线程在读 本地CPU缓存的 volatile字段时,就必须读取更新过的字段。

    具体是  在出现volatile字段的地方加入一条CPU指令:内存屏障(通常称为membar后fence),一旦volatile字段变化,就会触发CPU缓存更新

 

缺点:

  1. 频繁更改、改变或写入volatile字段 有可能导致性能为题。(volatile字段未修改时,读取没有性能问题的)
  2. 限制现代JVM的JIT编译器对这个字段优化(volatile字段必须遵守一定顺序,但这也是优点,或者说是特点吧!本来就是要保证happen-before,放置顺序指令重拍导致bug 例如单例双检测bug

性能优化:

  1. 减少对volatile的写操作
  2. 重构避免使用volatile

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值