JAVA并发容器源码分析【二】ConcurrentHashMap分析之CAS原理
锁的产生
锁,是为了解决并行运算时,数据并发读写的安全性问题。
锁的分类
在实现锁的技术中,分为乐观锁与悲观锁,悲观锁总是假设坏的情况,认为同一份数据在并发情况下一定会有修改,而乐观锁则相反,认为那份数据不会发生修改,在更新数据时会采用尝试不断重试的方式更新数据。
JAVA中的各种锁都是悲观锁,乐观锁是通过CAS技术实现。
CAS
CAS(Compare And Swap,比较交换):多个线程尝试使用CAS同时更新同一份数据时,只有其中一个线程能更新数据的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以重复尝试修改数据的值。CAS 操作中包含三个操作数 —— 需要读写的内存位置(V)、进行比较的预期原值(A)和拟写入的新值(B)。如果内存位置V的值与预期原值A相匹配,那么处理器会自动将该位置值更新为新值B。否则处理器不做任何操作。
Java中的CAS
Java中CAS操作通过JNI本地方法实现:
1 | unsafe.compareAndSwapInt(this, valueOffset, expect, update) |
CAS的缺点
1. ABA问题
你拿着一个装满钱的手提箱在飞机场,此时过来了一个火辣性感的美女,然后她很暖昧地挑逗着你,并趁你不注意的时候,把用一个一模一样的手提箱和你那装满钱的箱子调了个包,然后就离开了,你看到你的手提箱还在那,于是就提着手提箱去赶飞机去了。
看似没有问题,其实已经改变过了,解决办法:增加版本号。
2. 循环时间长时开销大
自旋CAS如果更新不成功,就一直重新循环,直到成功,如果长时间不成功,会给CPU带来非常大的执行开销。解决办法:网上查说用处理器提供的pause指令,这块不懂了。
3.只能保证一个共享变量的原子操作
java中的AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行CAS操作。这个类目前还没主动的使用过。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ClawHub的技术分享!