原子操作与锁

原子的意思是说“不能被进一步分割的粒子”,而原子操作是说“不可被终端的一个或多个系列的操作”。假定有两个操作 A 和 B,如果从执行A的线程来看,当另一个线程执行 B 时,要么将 B 全部执行完,要么完全不执行 B,那么 A 和 B 对彼此来说是原子的。

java 中可以通过锁,锁机制的方式来实现原子操作,但是有时候需要更有效灵活的机制,synchronized 关键字是基于阻塞的锁机制,也就是说当一个线程拥有锁的时候,访问同一资源的其它线程需要等待,直到该线程释放锁,因为 synchronized 关键字具有排他性,如果有大量的线程来竞争资源,那CPU将会花费大量的时间和资源来处理这些竞争,同时也会造成死锁的情况。而且锁的机制相当于其他轻量级的需求有点过于笨重 。

实现

使用 CAS 实现原子操作,利用处理器提供的 CMPXCHG 指令来实现,每一个 CAS 操作过程都包含三个运算符:一个内存地址 V,一个期望的值 A 和一个新值 B,操作的时候如果这个地址上存放的值等于这个期望的值A,则将地址上的值赋为新值 B,否则不做任何操作。
CAS 原子操作 (CompareAndSet) - 图1

问题

  1. ABA 问题

image.png

  1. 持续进行循环的开销
  2. 当对一个共享变量执行操作时,我们可以使用循环 CAS 的方式来保证原子操作,但是对多个共享变量操作时,循环 CAS 就无法保证操作的原子性,这个时候就可以用锁。还有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如,有两个共享变量 i=2,j=a,合并一下 ij=2a,然后用CAS来操作ij。