Java 并发编程 第二期:CAS与乐观锁

在讲解 CAS 和乐观锁之前,我们首先需要了解一些基本概念:Java 线程模型以及为什么需要线程模型

Java 线程模型

我们常说线程是进程的子集,一个进程可以有多个线程。但是对于 Linux 系统而言,并没有线程这个概念。我们可以说,在 Linux 中线程等于轻量级的进程。区别在于:

进程拥有独立的内存地址 ,但是线程没有独立的内存地址,多个线程只能共享一个内存的地址。

image.png
如图所示,Java 是运行在操作系统中的,那么其线程也对应着操作系统中的每一个线程。对应的,Java线程模型和内核必然存在着某种关系,一般我们认为有三种:一对一模型、多对一模型、多对多模型。

一对一模型

image.png

最简单的内存模型。好处是当某个线程阻塞时,另一个线程不受影响,可以继续执行其任务。缺点是一个用户线程就要开辟一个对应的内核线程,如果线程太多,会导致 CPU 使用增大。

多对一模型

image.png

和一对一模型相比,多对一将一部分的用户线程进行管理,然后开辟出一个内核线程。线程管理放在用户线程上。这样的好处是降低了CPU 的使用,提高了使用效率。但是缺点在于,对应组线程中的某个线程一旦阻塞,那么整组的其他线程也会被同时阻塞,直到该线程恢复正常。

多对多模型

image.png

多路复用多个用户级线程到同样数量或更少数量的内核线程。这是线程模型的效率提升的“终极模式”,它大幅度降低了系统资源的占用。

目前 Java 线程模型 为 一对一模型

无锁编程

在之前的第一期中我们讲过,无锁能够大幅度降低线程的开销,减少操作系统内核态和用户态的切换,极大提升多线程并发的性能。但是最大的难处在于:无锁编程难度相对较高,控制更加复杂,更容易出错。

悲观锁

image.png

如图所示,当多个线程访问目标资源时,如果我们使用互斥锁,那么当某个线程获取到目标资源后,就会对资源进行加锁,防止其他线程使用。只有当该线程使用结束,并释放资源后,其他线程才能继续去竞争获取资源。我们将这种情况称之为悲观锁
image.png

CAS

image.png

CAS,全称是compare and swap。和互斥锁不同,CAS 是一种乐观锁。当多个线程访问目标资源时,它首先会访问目标资源是否是之前的值(Compare 阶段),如果是的,那么就将其替换为自己的值;否则,就自旋等待,直到下次能够再次获取(Swap 阶段)。
一个简单的 CAS demo 如下图所示:

image.png
但是 这又引起一个问题:

CAS 分为 compare 和 swap 两步操作,多线程下难以保证一致性?

其实现有的操作系统已经为我们创建了对应的原子操作。例如 x86 系统使用的指令是cmpxchg,arm 使用的指令是LL/SC。通过不同操作系统提供的原子指令,我们无须担心CAS 操作的原子性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

君若雅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值