之前讲过解决线程安全问题(原子性)的办法之一Synchronized也就是我们所说 的锁,同步互斥的方式。今天我们介绍一下非阻塞同步的方式也就是无锁的方式解决
CAS
什么是CAS
CAS的全称为Compare-And-Swap,直译就是对比交换。是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值,经过调查发现,其实现方式是基于硬件平台的汇编指令,就是说CAS是靠硬件实现的,JVM只是封装了汇编调用,那些AtomicInteger类便是使用了这些封装后的接口。
简单解释一下,现在假如有两个线程,每一个线程都可以读写一个共享的变量a
.现在线程A要修改a
,线程要首先获取a
的值,然后进行修改,我们在提交修改结果之前呐,要在获取一遍最新值并与我们之前获取的值比较,相等就说明别的线程没有对a
进行修改,我们就可以大胆的在线程A中操作了,反之不相等,说明别的线程对值进行了修改,cas就会把别的线程修改后的最新值获取到然后在进行修改。
乐观锁与悲观锁
悲观锁:即认为数据发生冲突的概率很大,所以在读操作之前就上锁。synchronized和ReentrantLock都是悲观锁的典型例子。
乐观锁:即认为数据发生冲突的概率比较小,读操作之前不上锁。
写操作时,再判断数据在此期间是否被其它线程修改。被修改就读出来,未被修改则写回去。判断数据修改,同时写回新值,这两个操作要合成一个原子操作,也就是CAS。
形象的说一句,乐观锁就是我这个线程让别的线程修改共享数据,改完我获取最新的值,就不会产生安全问题了,而悲观锁是我这个线程提防别的线程改,一旦我获得了锁,别的线程要想操作共享数据就必须我操作完了把锁释放了,你又获取锁了,你才能修改。
AtomicInteger是典型的乐观锁实现。
原子类导图

AtomicInteger
public final int get():获取当前的值
public final int getAndSet(int newValue):获取当前的值,并设置新的值
public final int getAndIncrement():获取当前的值,并自增
public final int getAndDecrement():获取当前的值,并自减
public final int getAndAdd(int delta):获取当前的值,并加上预期的值
void lazySet(int newValue): 最终会设置成newValue,使用lazySet设置值后,
可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
大部分api都可以参考http://www.itsoku.com/article/182,这篇文章写得很详细
我打算以后再重新写一篇关于原子类更多的文章,这一篇权当是一个初步理解(我感觉乐观锁和悲观锁的理解还是挺通透的)
网友评论