乐观锁采用的机制就是CAS,compare and Swap 比较与交换
原理
cas 操作包含三个操作数 内存位置V、预期原值A、新值B。如果内存位置的值与预期值相同,那么处理器会将当前位置的值更新为新值,否则报错或自定义方法进行处理。
理解:多线程情况下,各个线程执行时,首先读取主存值(V=0),放入线程栈中(A=0),然后执行各自代码(即:线程一、线程二分别将自身线程栈中B的值赋给主存中的V),假若线程一和线程二同时开始执行,线程二因其他原因阻塞,线程一进行操作(再次读取主存中V值,与线程栈中A值对比,V=0 A=0匹配 ,将B=2赋给V ,主存中V=2),处理结束,线程二此时进行操作(重新读取主存中V=2,与线程栈中A=0对比,不匹配,则不要更改该位置,只告诉我这个位置现在的值)
由于CAS操作属于乐观派,它总认为自己可以完成操作,当多个线程同时使用CAS操作一个变量时,只会有一个胜出,并成功更新,其余均会失败,单失败的线程并不会被挂起,仅仅时被告知失败,并且可以再次进行尝试,当然也允许失败就放弃操作,基于这样的原理,CAS即使没有锁的存在,同样知道其他线程对共享资源操作影响,并执行相应的处理措施
CPU指令对CAS的支持
或许我们可能会有这样的疑问,假设存在多个线程执行CAS操作并且CAS的步骤很多,有没有可能在判断V和E相同后,正要赋值时,切换了线程,更改了值。造成了数据不一致呢?答案是否定的,因为CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。所以利用CPU的CAS指令,同时借助JNI来完成Java的非阻塞算法。而整个java.util.concurrent(J.U.C)都是建立在CAS之上的,因此相对于synchronized阻塞算法,J.U.C在性能上有了很大的提升