串一串java的voliate,cas,原子类

cpu是如何使用内存的

谈voliate之前就不得不谈一谈cpu和们的主存之间的关系。CPU的运算处理速度与内存读写速度的差异非常巨大,为了解决这种差异充分利用CPU的使用效率,就开始在CPU处理器和内存之间加了一层缓冲区。
注意:所以所谓的本地内存,主内存都是抽象概念,并不一定就真实的对应cpu缓存和物理内存。当然如果是出于理解的目的,这样对应起来也无不可。
在这里插入图片描述
但是高速缓存在解决cpu的内存速度不一致问题的同时,也引起了新的问题,那就是共享数据的不一致性。解决这个问题最简单的方法是用Synchronized关键字。Synchronized关键字能同时解决程序执行的“原子性”,“可见性”,和“有序性”。当我们获得锁的时候,执行同步代码,线程会被强制从主内存中读取数据,先把主内存的数据复制到本地内存,然后在本地内存进行修改,在释放锁的时候,会把数据写回主内存。但是这样做的效率无异会很低。这时候就引入了voliate

voliate

前面说了,如果要解决共享数据的安全性,要保证三个条件:可见性,有序性 和 原子性。
voliate能保证可见性和有序性

  1. 可见性保证:

    • CPU对volatile修饰变量的内存副本修改会立刻同步回主内存。
    • 对其他核心立即可见,这个的意思是,如果其他核心如果缓存了被修改的volatile修饰变量,那其他核心副本就会立刻失效。然后从主存中获取最新的数据。
  2. 有序性保证:
    主要就是防止指令重排。有volatile修饰的变量,赋值操作后加内存屏障,防止内存屏障后面的语句重排到赋值操作之前。防止在拿到变量之后赋值操作还没完成。
    举个例子:
    在单例模式中,Instance inst = new Instance(); 这一句,就不是原子操作,它可以分成三步原子指令:
    1,分配内存地址;
    2,new一个Instance对象;(这里加内存屏障)
    3,将内存地址赋值给inst;

但是voliate是没法保证原子性,例如像n++这种组合操作。
针对num++这类复合类的操作,可以使用java并发包中的原子操作类原子操作类是通过循环CAS的方式来保证其原子性的。

CAS方式

CAS指令执行时,当且仅当内存地址V的值与预期值A相等时,将内存地址V的值修改为B,否则就什么都不做。整个比较并替换的操作是一个原子操作。
CAS方式的原子性在api层面是无法实现的。因为判断相等到值替换中间我们的数据有可能被其他线程更改。所以cas实际上是从硬件层面或者说cpu层面来实现的。

这个操作主要是通过:c++编写的Atomic::cmpxchg指令实现的,这个指令在不同架构的cpu下实现不一样。使用该方法的大体上逻辑如下:
1.通过判断是否是多核cpu来给决定是否给该方法上锁标志。因为单核情况下一次只有一个线程能运行,在判断和赋值中间一般不会发生中断而导致切换线程,所以不用担心属数据被更改。
2. 如果遇到带有lock前缀的指令,那在此期间会锁定从cpu通往内存的总线(总线锁定)。但是锁定总线代价较高,其他cpu上运行的线程即便访问的不是共享数据,也是无法通过总线来访问数据。为此引入了缓存锁定,只需要锁定缓存在cpu本地内存数据对应的主内存数据即可。

voliate和cas机制的典型应用——原子类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值