锁的产生

锁,是为了解决并行运算时,数据并发读写的安全性问题。

锁的分类

在实现锁的技术中,分为乐观锁与悲观锁,悲观锁总是假设坏的情况,认为同一份数据在并发情况下一定会有修改,而乐观锁则相反,认为那份数据不会发生修改,在更新数据时会采用尝试不断重试的方式更新数据。

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操作。这个类目前还没主动的使用过。