并发编程(2)-CAS

1.What-CAS是什么?


CAS是英文翻译是Compare And Swap的缩写,也就是比较并交换的意思。它是一个机制,是个负责同步的机制,再加一条,它还是一个非阻塞同步的机制。既然说到了,非阻塞同步,那什么是阻塞同步呢?我们知道在Java中,如果想确保一段代码或者一个方法,在多线程并发的场景下,在某个时间段,只由一个线程运行,我们通常采用的方法是加上synchronized关键字。

举个例子:

看下面这段代码,我们期待的结果是count = 100,但最后的结果往往不是100.


运行了一次上面的代码,结果是90,当然也可能是其他值。因为上面的代码不能保证在多线程并发的场景下,count++的原子性,实际上count++本身不是一个原子类型的操作,它有好几个步骤,导致结果不可预知。


怎么样才能保证最后得到的值一定是100呢?加个锁,比如synchronized,来保证下一个执行count++的线程是在当前线程执行完完整的count++操作后,再去执行count++操作,而不是在当前线程还没有执行完count++,又有其他线程执行count++,导致最后的值小于100。

加上锁后:


运行结果100,达到了预期要求。

注意:

在加上synchronized后,当有某个线程获取了锁,并执行count++的过程中,其他线程如果也要执行count++,只能阻塞等待,在执行线程释放锁之前,其他线程什么也做不了。这就是阻塞^_^。而CAS提供了一种非阻塞的方式。


2.How-CAS机制是怎么运作的?


场景:变量a是一个多线程共享的变量,每个线程在执行代码的时候,都会对共享变量a进行加1操作,变量a保存在内存地址为0xA002的地方,a的当前值是100。


此时线程0开始执行,从内存中取出值100,100对于线程0来说,就是旧的预期值;线程0将100加1,得到101,101就是要修改的新值;得到新值后,线程0准备将新值101放入内存,but。。。在此之前,另一个线程1,已经将当前的内存值更新为了101。那线程0还更新吗?更新,但不会成功,注意这里所说的更新是一系列操作,并不是直接将值改成101。这个更新操作由以下几个步骤组成。

i>Compare(比较):将旧的预期值100,和地址0xA002地址保存的实际值,进行比较。

ii>Swap(交换):只有当旧的预期值和地址0xA002地址保存的实际值相等时,才进行交换;因为当前值已经变更为了101,不等于旧的预期值100,所以此次不交换,也就是没有更新成功。

iii>重新取值:线程0更新失败,重新从0xA002地址取值,取到新值101。再开启新一轮的加1->比较->swap等操作,这个过程就是自旋


3.Example-CAS实例


AbstractQueuedSynchronizer中就有几个Compare And Set方法,原理和上面讲的一样一样的^_^。


这里面的compareAndSet方法,调用的都是unsafe的方法,那这个unsafe是个什么东东?


可以参考这两篇文章,讲的很详细

1)http://blog.csdn.net/dfdsggdgg/article/details/51538601

2)http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/

这个类的大部分方法都是native实现,native方法绕开了JVM,效率上会有一定提升。