Synchronized和ReentrantLock可重入锁

1. 作用:

用于修饰方法或代码块,确保在同一时刻只有一个线程能够执行该方法或代码块,实现互斥访问。

2. synchronized底层,会不会牵扯到 os 层面

会,synchronized 升级为重量级锁时,依赖于操作系统的互斥量——mutex 来实现,mutex 用于保证任何给定时
间内,只有一个线程可以执行某一段特定的代码段。

3. synchronized如何保证可见性?

Step 1: 加锁时,线程必须从主内存中读取数据。

Step 2: 释放锁时,线程必须将修改的数据刷回主内存。

4. synchronized如何保证有序性?

synchronized 通过 JVM 指令 monitorenter 和 monitorexit,来确保加锁代码块内的指令不会被重排。

5. synchronized 怎么实现可重入的呢?

可重入意味着同一个线程可以多次获得同一个锁,而不会被阻塞。

synchronized 之所以支持可重入,是因为 Java 的对象头包含了一个 Mark Word,用于存储对象的状态,包括锁信息。
当一个线程获取对象锁时,JVM 会将该线程的 ID 写入 Mark Word,并将锁计数器设为 1。 如果一个线程尝试再次获取已经持有的锁,JVM 会检查 Mark Word 中的线程 ID。如果 ID 匹配,表示的是同一个线程,锁计数器递增。
当线程退出同步块时,锁计数器递减。如果计数器值为零,JVM 将锁标记为未持有状态,并清除线程 ID 信息。

6. synchronized锁升级过程‼️

无锁 ——> 偏向锁(记住你了,熟客专用) ——> 轻量级锁(在线排队) ——> 重量级锁(去休息室等叫号)

为了提升 synchronized 的性能,引入了锁升级机制,从低开销的锁逐步升级到高开销的锁,以最大程度减少锁的竞争。没有线程竞争时,就使用低开销的“偏向锁”,此时没有额外的 CAS 操作(同一个线程可以多次获取同一把锁,无需重复加锁);轻度竞争时,使用“轻量级锁”,采用 CAS 自旋,避免线程阻塞;只有在重度竞争时,才使用“重量级锁”,由 Monitor 机制实现,需要线程阻塞。

1️⃣ 无锁状态,对象未被锁定,Mark Word 存储对象的哈希码等信息。

2️⃣ 偏向锁,当一个线程第一次获取锁时,JVM 会在对象头的 Mark Word 记录这个线程 ID,下次进入 synchronized 时,如果还是同一个线程,可以直接执行,无需额外加锁。

3️⃣ 轻量级锁,当多个线程尝试获取锁但不是同一个时段,偏向锁会升级为轻量级锁,等待锁的线程通过 CAS 自 旋避免进入阻塞状态。

4️⃣ 重量级锁,如果自旋失败,锁会升级为重量级锁,等待锁的线程会进入阻塞状态,等待监视器 Monitor 进行调度。

7. synchronized 和 ReentrantLock 的区别

1️⃣ synchronized 由 JVM 内部的 Monitor 机制实现,ReentrantLock基于 AQS 实现。

2️⃣ synchronized 可以自动加锁和解锁,ReentrantLock 需要手动 lock() 和 unlock() 。

8. 并发量大的情况下,使用 synchronized 还是 ReentrantLock?

ReentrantLock,因为:
ReentrantLock 提供了超时和公平锁等特性,可以应对更复杂的并发场景。
ReentrantLock 允许更细粒度的锁控制,能有效减少锁竞争。
ReentrantLock 支持条件变量 Condition,可以实现比 synchronized 更友好的线程间通信机制。

9. Lock 了解吗?

Lock 是 JUC (Java 并发工具包)中的一个接口,最常用的实现类包括可重入锁 ReentrantLock、读写锁 ReentrantReadWriteLock
等。

lock 方法会首先尝试通过 CAS 来获取锁。如果当前锁没有被持有,会将锁状态设置为 1,表示锁已被占用。否则,会将当前线程加入到 AQS(抽象队列同步器) 的等待队列中。(CAS获取——>AQS等待)

10. AQS 了解多少?

AQS 是一个抽象类。AQS 的思想是,如果被请求的共享资源处于空闲状态,则当前线程成功获取锁;否则,将当前线程加入到等待队列 中,当其他线程释放锁时,从等待队列中挑选一个线程,把锁分配给它。

11. ReentrantLock 的实现原理

ReentrantLock 是基于 AQS 实现的可重入排他锁,使用 CAS 尝试获取锁,失败的话,会进入 CLH 阻塞队列,支持公平锁、非公平锁,可以中断、超时等待。

12. 非公平锁和公平锁有什么不同?

公平锁意味着在多个线程竞争锁时,获取锁的顺序与线程请求锁的顺序相同,即先来先服务。 非公平锁不保证线程获取锁的顺序,当锁被释放时,任何请求锁的线程都有机会获取锁,而不是按照请求的顺序。

如何实现非公平锁?

实现非公平锁的关键在于不检查 AQS 等待队列的状态。在线程尝试获取锁(tryAcquire)时,直接通过 CAS 修改 state 变量。如果修改成功,就视为获取锁成功。

补充:

对象锁的核心:Monitor
在 JVM 层面,每个对象都关联着一个 Monitor(监视器)。

当线程 A 想要执行被 synchronized 保护的代码时,它必须先去拿这个对象的 Monitor。

如果拿到了,锁计数器就从 0 变成 1,这个线程就成了锁的拥有者。

其他线程再想拿这把锁,就只能在外面排队等待(Entry Set)。

#牛客AI配图神器#
全部评论

相关推荐

暑期实习什么时候投?
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务