多线程--乐观锁与乐观锁的一种实现方式-CAS

1:乐观锁的概念

乐观锁,顾名思义就是很乐观,我们认为通常情况下其它线程不会修改我们正在操作的数据(也就是不会发生并发冲突),所以不会上锁。但是为了保证线程安全,我们会在更新数据之前判断一下其它线程有没有修改我们的数据。可以使用版本号机制。

也就是说,乐观锁假设数据大概率不会发生并发冲突,所以只会在更新数据的时候检测是否发生了并发冲突,如果发现了并发冲突,则返回用户错误的信息,让用户决定怎么做。

乐观锁是一种常见的锁策略,它代表了一种关于锁的思想。而这种思想的核心可以概括为:冲突检测+数据更新。我们可以在下面的CAS实现乐观锁中深入体会这种思想。

2:乐观锁的实现-CAS(Compare And Swap 比较并交换)

首先声明,CAS是乐观锁技术,不是乐观锁。乐观锁是一种思想,而CAS是该思想的实现。

1.CAS基础逻辑

当多个线程都使用CAS来操作数据时,只会有一个线程成功修改数据,但其它修改失败的线程并不会挂起,而是会被告知本次竞争失败,可以再次尝试。

CAS的操作中包含三个操作数:V(当前内存中实际存储的值),A(我们预期内存中存储的值),B(我们要对内存数据进行修改的值)。我们会先让V与A比较,如果V==A,则我们认为内存中的数据没有被修改,并且将V的数据修改为B;否则我们认为内存中的数据已经被修改了,不做任何操作。不论哪种情况,我们都会在执行CAS操作之前返回V的值。也就是说,我认为V中应该包含A,如果包含,则将B放到这个位置,否则不要更改该位置,只要告诉我这个位置现在的值就好。这符合乐观锁的核心思想:冲突检测+数据更新。

我们可以结合源码来理解一下,下面截图是 AtomicInteger 类中的 compareAndSet()方法,该类使用的就是CAS技术

注释:

方法介绍:

 方法参数:

 方法返回值:

2.ABA问题及解决方法

(1):ABA问题

我们来看如下例子,来帮助我们理解ABA问题。

假设有这样一个链表

有线程T1,它已知该链表的 head==[A],它现在想删除节点[A],让B成为头节点。但此时T1的时间片用完了,轮到线程T2执行,而T2把整个链表都替换成了新的链表(如下图所示)

这时又该T1执行了,它判断 head==[A] 所以认为没有人修改该链表,于是它进行了该操作 head=[B],但B.next==null,这就相当于丢弃了T2修改后的链表数据,是线程不安全的。

(2):解决方法

我们可以使用 AtomicStampedReference 这个类 来解决ABA问题。

该类的部分注释:

 根据官方注释我们可以看到,该类维护了一个对象的引用和一个整型(版本号),我们可以根据这两个数据综合来判断数据是否被修改过。

下面是该类实现的 compareAndSet()方法

注释:

方法介绍:

方法参数:

 方法返回值:

 

注:本人是在校学生,对相关知识难免有疏漏或者理解错误,如有发现,还望指正,谢谢。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值