CAS
1、什么是CAS?
CAS:又叫 campare and set/Swap/Exchange;
ABA 问题的解决办法:加版本号。如,每改变一次,自身版本号就 加1。而是否对最后结果有影响(是否更新为新值)需要程序员自己判断。
如果程序员觉得没什么影响,只要结果还是A那就行,如果程序员觉得如果有改变,心里膈应,那就不行。
2、使用原子类的底层实现原理
以AtomicInteger 为例:
代码如下,为了实现线程安全,我们使用了原子类AtomicInteger ,而且变量增加使用了AtomicInteger 类的类方法 incrementAndGet()。
接下来我们就对incrementAndGet() 一探究竟。
按住ctrl + 单击该方法,跳转到AtomicInteger.java类中:
再点进去unsafe.getAndAddInt()方法,跳转到unsafe.class类中:
这里有一个循环,条件是做一个CAS 操作。再点击进去,找到是当前类的一个native方法。
这是什么意思呢?native表示这是用C/C++写的底层代码调用。
似乎到这里断了,不过为了一探究竟,我们继续找到了C代码。
在Java里是unsafe类的compareAndSwapInt(),在底层代码里对应的是unsafe.cpp文件中:
我们观察到第1217行可知:最后调用的是Atomic::cmpxchg()方法,熟悉C/C++的话,就知道,这是stomic.cpp文件中的cmpxchg方法。
再点进去追击:
可看到第56行是cmpxchg()方法,一路追踪,我们可发现,到最后是到了atomic_linux_x86.inline.cpp文件中。
找到Atomic.cpp文件中的cmpxchg()方法。
在这里我们看:
在第95行有个LOCK_IF_MP() ,这其实是个宏定义,意思是是否是多核(Multi Processor):
再继续追击,最后,我们知道最终的实现是依靠底层的 lock cmpxchg 指令(CPU级别)。
虽然我们从代码可知,在多核(CPU)时才加lock,单核(CPU)不加。如:6 核12线程,我们在这里视为12核。故,单核情况下,指的就是自己线程不会打断自己。
cmpxchg 并不是原子性的,保证原子性还是依靠前面的 Lock。所以,我们才说底层代码直接支持CAS,是一把悲观锁,可以是缓存锁,也可以是总线锁。
Over......