Java的CAS(比较交换)

一、什么是CAS

使用锁时,线程获取锁是一种悲观锁策略,而CAS操作(又称为无锁操作)是一种乐观锁策略,使用CAS(compare and swap)又叫做比较交换来鉴别线程是否出现冲突,出现冲突就重试当前操作直到没有冲突为止。

CAS:Compare And Swap(比较交换机制)——乐观锁策略

悲观锁(如JDK1.6之前的内建锁):假设每一次执行同步代码块均会产生冲突,所以当线程获取锁成功,会阻塞其他尝试获取该锁的线程

乐观锁(如Lock):假设所有线程访问共享资源时不会出现冲突,既然不会出现冲突自然就不会阻塞其他线程。线程不会出现阻塞状态。

CAS(无锁操作):使用CAS叫做比较交换来判断是否出现冲突,出现冲突就一直重试当前操作,直到不冲突为止。

二、CAS的操作过程

一般来说,CAS交换过程有三个阶段V、O、N

V;内存中地址存放的实际值

O:预期值(旧值)

N:新值,表示我们准备更新V的值

当执行CAS后,如果V == O ,即旧值与内存中实际值相等,表示上次修改后没有任何线程再次修改此值,因此可以将N替换到内存中。

如果  V != O,表示该内存中的值已经被其他线程做了修改,所以无法将N替换,返回最新的值V

当多个线程使用CAS操作一个变量时,只有一个线程会成功,并成功更新变量值,其他线程均会失败。失败线程会重新尝试或将线程挂起(阻塞)

三、CAS存在的问题

1.ABA问题:一个旧值A变为了成B,然后再变成A,刚好在做CAS时检查发现旧值并没有变化依然为A,但是实际上的确发生了变化。

解决思路:沿用数据库的乐观锁机制,添加版本号1A-2B-3A,JDK1.5提供atomic包下AtomicStampedReference类来解决CAS是ABA问题

2.自旋(不断重试)会浪费大量的处理器资源

与线程阻塞相比,自旋会浪费大量的cpu资源。因为此时线程仍处于运行状态,只不过跑的是无用指令,期望在无用指令时,锁能被释放出来。

解决思路:自适应自旋,根据以往自旋等待时能否获取到锁,来动态调整自旋时间(循环尝试数量)

具体策略:如果在上一次自旋时获取到锁,则此次自旋时间稍微变长一点;如果在上一次自旋结束还没有获取到锁,此次自旋时间稍微短一点。

3.公平性

处于阻塞状态的线程无法立刻竞争被释放的锁;而处于自旋状态的线程很有可能先获取到锁。内建锁无法实现公平性,而lock体系可以实现公平锁。

四、元老级的内建锁(Synchronized)最主要的问题:

   线程存在竞争的情况下会出现线程阻塞以及唤醒带来的性能问题,是一种互斥同步(阻塞同步),效率很低

   而CAS并不是武断的将线程挂起,会尝试若干次CAS操作,并非进行耗时的挂起与唤醒操作,因此是非阻塞式同步

猜你喜欢

转载自blog.csdn.net/eve8888888/article/details/84578134