多线程基础——CAS

CAS概念:

CAS全称Compare And Swap,中文是对比并交换,是乐观锁的一种,是说多线程之一在写入修改值前先判定内存位置V中的值是否是预期值,是则修改V中的值,否则获取V中的值重复CAS。

CAS的过程是:(1) 线程读取内存位置V中当前值E到线程内部,然后修改E,写回内存前再次获取位置V的值,假如是N,判断N\==E?,如果N\==E,说明没有其他线程修改位置V的值,执行写回操作。CAS流程图如下(来自马士兵老师公开课程)

CAS.jpg

ABA问题

ABA是:如果线程1第二次获取位置V处的值依旧是E,但是这个E应不是一开始的E了,它可能被线程2变换了两次,举个例子就是E-> X -> E,但是线程1并不知道,然后修改了内存V的值,这个过程就发生了ABA问题。ABA问题的解决方式可以利用版本号或者时间戳。相关类有 AtomicStampedReference.

CAS原理

CAS是使用JDK类UnSafe实现的,UnSafe类是使用C++代码实现的,往更底层来讲,是通过汇编代码实现的。

Unsafe类中对应的代码是:

1
2
3
4
5
6
7
8
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) {
int mp == os::is_MP();
__asm__ volatile (LOCK_IF_MP(%4)) "cmpxchgl %1,(%3)"
: "=a" (exchange_value)
: "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
: "cc", "memory");
return exchange_value;
}

关键在于:(LOCK_IF_MP(%4)) “cmpxchgl %1,(%3)”。

这说明CAS的底层实现还是依靠汇编指令cmpxchg

LOCK_IF_MP是说:如果多线程(MP=Multi Processor),则需要在汇编命令cmpxchg前加上lock

因此,关键指令就是lock cmpxchg

lock指令可以保证线程执行CAS的过程不受干扰,即加上锁,避免线程写回内存过程位置V处的值发生改变。

lock的硬件原理是:lock指令在执行后面指令的时候锁定一个北桥信号,网上也说是锁内存总线或者cache,这部分去网上翻了翻,大致找到了以下几个资料:

  1. 计算机总线结构详解
  2. lock指令
  3. x86系统cache locking的原理

感谢马老师。