CAS(compare and swap;比较并交换) 也就是我们通常说的自旋锁,用来替代重量级锁,如图所示:
比如 我们有一个值 i 每次都做i++的操作,多个线程都来做操作时i 的值就会出问题,我们通常会写synchronized(i++),那么CAS怎么操作呢?下面我们来讲一下:线程在操作时 先读取i 的值,然后计算,然后再去读取i 的值 看看i 的值 是否跟刚刚读取的i 的值一致,如果不一致说明有其他线程在你操作期间也进行了操作,那么重新读取计算,一致那就很美,直接更新
这里有个很经典的ABA问题,就是别的线程修改值的时候,最终结果与你读取的值一致,那么你比较的时候就会直接更新,这种情况怎么来解决呢,最简单的办法就是加一个版本号,
这样你就知道这个值到底有没有被别的线程修改过。当然ABA 问题要根据实际情况来处理,如果你的业务需求不关心过程,那么你就不需要考虑这个问题,直接干就完了。
看到这里不知道大家心里是否有疑惑,如果我在比较完和写入结果之间有其他线程将i修改了,你依然将结果写入了,这时候就不对了。所以比较并交换的过程必须是原子性的,那这个事他是怎么做到的呢,我写了一些例子给大家看一下
例子是创建100个线程,然后每个线程去n进行了一万次的+1,最后的结果显然应该是100万,
图一是线程不安全的,大家可以脑补一下结果,这里我告诉大家每次执行的结果都是不一样的,图二是加了synchronized 执行结果当然是100万了,图三是使用了AtomicInteger,同样得到结果100万,他没加锁就可以做到线程安全,这里我调用的方法incrementAndGet(),我们点进去看看他的源码是怎么是实现的
如图
他调用了compareAndSwapInt这个方法,大家看名字不就是我们上面说的CAS嘛,再点就是native 修饰的方法了,感兴趣的朋友可以去了解一下再往下走就是调用的c++ 的一个CAS的方法,再往下就是
汇编码的一个CAS的实现,最终实现是一个lock cmpxchg 指令; 别问我是怎么知道的,问就是百度。哈哈!
最后再说明一下虽然CAS和synchronized最终都会到汇编指令,但是CAS没有经过操作系统的线程管理,所以
他是轻量级的,而synchronized经过了操作系统的线程管理,这个管理过程是不必要的,所以他是重量级的,大家
不要搞混淆了哦!