【JavaEE精炼宝库】多线程进阶(1)常见锁策略 | CAS | ABA问题

目录

一、常见的锁策略:

1.1 悲观锁 | 乐观锁:

1.2 重量级锁 | 轻量级锁:

1.3 自旋锁 | 挂起等待锁:

1.4 公平锁 | 非公平锁:

1.5 可重入锁 | 不可重入锁:

1.6 互斥锁 | 读写锁:

1.7 面试题:

二、CAS

2.1 CAS 的概念:

2.2 CAS 的实现的:

2.3 CAS 的应用:

2.3.1 实现原子类:

2.3.2 实现自旋锁:

2.4 CAS 的 ABA 问题:

2.4.1 ABA 问题的概述:

2.4.2 ABA 问题引来的 BUG:

2.5 解决方案:

2.6 面试题:


终于进入到多线程的进阶了,这里面涉及到的内容面试容易考,但是工作中很少直接用到。

一、常见的锁策略:

注意:接下来讲解的锁策略不仅仅是局限于 Java 。任何和 "锁" 相关的话题,都可能会涉及到以下内容。这些特性主要是给锁的实现者来参考的。我们了解一些,也能更加合理的使用锁。

1.1 悲观锁 | 乐观锁:

加锁的时候,预测当前锁冲突的概率是大还是小。

• 悲观锁:

预测当前锁的冲突概率大,后续要做的工作往往就会更多。加锁的开销就会更大(时间,系统资源)。

• 乐观锁:

预测当前锁的冲突概率不大,后续要做的工作往往就会更少。加锁的开销就会更小(时间,系统资源)。

synchronized 初始使用乐观锁策略。当发现锁竞争比较频繁的时候,就会自动切换成悲观锁策略。所以 synchronized 既是乐观锁也是悲观锁,支持自适应。

1.2 重量级锁 | 轻量级锁:

一般来说,悲观锁往往就是重量级锁(加锁过程做的事情多),乐观锁往往就是轻量级锁(加锁过程做的事情少)。

锁的核心特性 "原子性",这样的机制追根溯源是 CPU 这样的硬件设备提供的。硬件有提供,软件层面才能实现。

• CPU 提供了 "原子操作指令"。

• 操作系统基于 CPU 的原子指令,实现了 mutex 互斥锁。

• JVM 基于操作系统提供的互斥锁,实现了 synchronized 和 ReentrantLock 等关键字和类。

注意:synchronized 并不仅仅是对 mutex 进行封装,在 synchronized 内部还做了很多其他的工作。  

• 重量级锁: 

加锁机制重度依赖了 OS 提供了 mutex。

这样做的特点有:1. 大量的内核态用户态切换。2. 很容易引发线程的调度。

这两个操作,成本比较高,一旦涉及到用户态和内核态的切换,就意味着 “沧海桑田”。 

• 轻量级锁:

加锁机制尽可能不使用 mutex,而是尽量在用户态代码完成,实在搞不定了,再使用 mutex。

这样做的特点有:1. 少量的内核态用户态切换。2. 不太容易引发线程调度。

为什么会有这样的好处呢?举个栗子:

想象去银行办业务。在窗口外,自己做,这是用户态,用户态的时间成本是比较可控的。在窗口内让工作人员做,这是内核态,内核态的时间成本是不太可控的(可能人家处理一半,去做别的事情了)。如果办业务的时候反复和工作人员沟通,还需要重新排队,这时效率是很低的。

重量级锁、轻量级锁和悲观锁、乐观锁的概念有重合的地方,面试的时候要能转的过来。

synchronized 开始是一个轻量级锁。如果锁冲突严重,就会变成重量级锁。

1.3 自旋锁 | 挂起等待锁:

• 自旋锁:

按之前的方式,线程在抢锁失败后进入阻塞状态,放弃 CPU,需要过很久才能再次被调度。但实际上,大部分情况下,虽然当前抢锁失败,但过不了很久,锁就会被释放。没必要放弃 CPU,这个时候就可以使用自旋锁来处理这样的问题。

自旋锁伪代码:

while (抢锁(lock) == 失败) {}

⼀旦锁被其他线程释放,就能第⼀时间获取到锁(线程没有被调度)。

自旋锁是一种典型的轻量级锁的实现方式。

优点:没有放弃 CPU,不涉及线程阻塞和调度,⼀旦锁被释放,就能第一时间获取到锁。

缺点:如果锁被其他线程持有的时间比较久,那么就会持续的消耗 CPU 资源,CPU 在空转。

synchronized 中的轻量级锁策略大概率就是通过自旋锁的方式实现的。

• 挂起等待锁:

是重量级锁的一种典型的实现方式,借助系统中的线程调度机制,当尝试加锁,并且锁被占用了,出现锁冲突,就会让当前这个尝试加锁的线程,被挂起(阻塞状态)。此时这个线程就不会参与线程调度了。知道这个锁被释放,然后系统才能唤醒这个线程,去尝试重新获取锁。

1.4 公平锁 | 非公平锁:

• 公平锁:遵守 "先来后到"。B 比 C 先来的。当 A 释放锁的之后,B 就能先于 C 获取到锁。

• 非公平锁:不遵守 "先来后到"。B 和 C 都有可能获取到锁。

其实这两个策略都挺公平的,只是最初的 Java 大佬把先来后到定义成公平,均等机会定义成不

评论 91
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值