原子操作实现原理

一些概念

  • CAS:

    Compare And Swap,比较并交换,CAS操作需要两个值,一个旧值和一个新值,比较期间先比较旧值有没有发生变换,如果没有发生变换,才交换新值,否则不变

  • 内存顺序冲突

    一般由假共享引起,假共享是指多个CPU同时修改同一个缓存行的不同部分而引起其中一个CPU的操作无效,当出现此冲突时,CPU必须清空流水线

处理器如何实现原子操作

使用基于对缓存加锁或者总线加锁的方式实现多处理器之间的原子操作,但复杂的内存操作处理器依旧不能保证其原子性,如跨总线宽度、跨页表的访问。

  • 使用总线锁

    使用处理器提供的一个LOCK#(#的意思是LOCK为前缀)信号,当一个处理器在总线上输出此信号时,其他处理器的请求将被阻塞住,那么该处理器可以独占共享内存,开销较大。

  • 使用缓存锁

    指内存区域如果缓存在CPU的缓存行中,并且在Lock操作期间被锁定,那么当它执行所操作回写到内存中,CPU不在总线上发出LOCK#信号,而是修改内部的内存地址,并允许它的缓存一致性机制来保证操作的原子性,因为缓存一致性机制会阻止同时修改由两个以上处理器缓存的内存区域数据

    但是有两种情况CPU不会使用缓存锁定:

    1. 操作的数据不能缓存在处理器内部或者数据跨多个缓存行,此时调用总线锁
    2. 部分处理器不支持缓存锁定

java中实现原子操作

java通过循环CAS实现原子操作,下面讲讲使用循环CAS实现的原子操作

CAS是利用了处理器提供的CMPXCHG指令实现的。自旋CAS实现基本思路就是循环进行CAS操作直至成功为止。

java中的原子类就是利用了此

CAS

CAS 操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论V值是否等于A值,都将返回V的原值

CAS 有效地说明了:我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可

当多个线程尝试使用CAS同时更新一个变量,最终只有一个线程会成功,其他线程都会失败。但和使用锁不同,失败的线程不会被阻塞,而是被告之本次更新操作失败了,可以再试一次。此时,线程可以根据实际情况,继续重试或者跳过操作,大大减少因为阻塞而损失的性能。所以,CAS是一种乐观的操作,它希望每次都能成功地执行更新操作。

CAS实现原子操作的三大问题

  1. ABA问题

    CAS需要操作值的时候,会先检查旧值,如果旧值在这段时间经过了由A->B->A的变化,则无法检测出来,为解决此问题,可以引入版本号,每次改变则修改一次版本,Atomic中有提供当前引用是否等于预期引用的思路

  2. 循环时间长开销大

    自旋CAS如果长时间不成功,会带来较多CPU消耗

  3. 只能保证一个共享变量的原子操作

AtomicIntegerArray

AtomicIntegerArray会将当前的数组复制一份,所以当AtomicIntegerArray对内部的数组元素进行修改时,不会影响传入的数组

你可能感兴趣的:(原子操作实现原理)