HelloCoder HelloCoder
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
随笔
关于作者
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
随笔
关于作者
  • 《LearnJavaToFindAJob》

    • 导读

    • 【初级】6~12k档

    • 【中级】12k-26k档

      • JVM进阶

      • Java进阶

        • ConcurrentHashMap面试题
        • CopyOnWriteArrayList的实现原理
        • HashMap的put过程是怎么样的?
        • IO模型有哪些?
        • Synchronized相关
        • ThreadLocal的原理
        • synchronized锁升级
        • valueOf、(String)强转有什么区别?
        • 为什么在lambda中使用的局部变量必须是final或有效final
        • 你知道如何更新缓存吗?如何保证缓存和数据库双写一致性?
        • 八股文之ReentrantLock
        • 分布式事务
        • 如何保障生产端消息投递成功?
        • 如何手动触发全量回收垃圾,如何立即触发垃圾回收
        • 数据库连接池为什么要使用ThreadLocal?
        • 线程池中多余的线程是如何回收的
        • 谈谈你对AQS的理解
        • 谈谈你对CAS的理解
        • util.concurrent的理解
        • 高并发下如何保证接口的幂等性?
      • MySQL

      • 中间件

      • 算法

      • 高阶

    • 【高级】26k+档

    • 大厂面试题

    • 求职建议

    • 面经

  • LearnJavaToFindAJob
  • 【中级】12k-26k档
  • Java进阶
#ReentrantLock #八股文之
码农阿雨
2022-06-02
目录

八股文之ReentrantLock

# ReentrantLock的原理是什么?

“ReentrantLock 是 java.util.concurrent 包下基于 AQS 实现的可重入互斥锁。**,通过一个volatile的state状态变量和一个CLH变体的双向等待队列来实现可重入的独占锁。**它主要用于替代 synchronized,但在功能上更加灵活和强大。”

# 核心实现机制

ReentrantLock 的核心原理可以概括为:AQS 框架 + CAS 原子操作 + state 状态机

1、AQS (AbstractQueuedSynchronizer)

AQS 维护了一个 volatile int state(同步状态)和一个 FIFO(先进先出)的线程等待队列(CLH 队列)。

CLH锁其实就是一种基于逻辑队列非线程饥饿的一种自旋公平锁。当多线程竞争一把锁时,获取不到锁的线程,会排队进入CLH队列的队尾,然后自旋等待,直到其前驱线程释放锁。

作用:AQS 负责管理阻塞队列、唤醒线程、维护同步状态,是锁的底层基础设施。

2、 CAS操作:

通过Unsafe类的CAS保证state变更的原子性(无锁原子算法)

3、state 状态管理:

使用一个volatile int state变量表示锁状态

  • state = 0:锁空闲
  • state > 0:锁被占用,重入次数
  1. 等待队列:基于CLH队列变体的双向链表,保存等待获取锁的线程

# 加锁流程

非公平锁流程:

“先CAS插队抢一次,抢不到再走 AQS 排队流程。

步骤 1: 尝试 CAS 抢占(非公平插队), AQS 的 state 状态从 0 变为 1。

步骤 2: 插队失败后,再次尝试及进入 AQS 核心流程,线程会进入 AQS 的 acquire(1)

步骤3: 还是失败,将线程包装成Node加入等待队列,进入自旋,不断尝试获取锁或挂起等待

公平锁:

# 与synchronized对比的优势

  1. 可中断:支持lockInterruptibly(),等待锁时可响应中断
  2. 超时机制:支持tryLock(timeout),避免无限等待
  3. 公平选择:可选择公平或非公平策略
  4. 多条件:一个锁可以关联多个Condition

# 公平和非公平锁

非公平锁是“先抢再说”。它不关心队列里有没有人,先抢一把,抢不到再排队。

公平锁是“先排队等候”。它确保了等待时间最长的线程优先获取锁。

特性 非公平锁(默认) 公平锁
抢锁时机 立即尝试 CAS 抢锁(插队)。 只有在队列为空时才尝试 CAS 抢锁。
队列检查 不检查队列,直接尝试抢。 严格检查队列,若有人排队则排队。
性能 吞吐量高。 吞吐量较低。
风险 可能导致排队线程“饥饿”。 保证了线程的绝对公平性。
设计理念 追求高性能。 追求严格的公平性。

获取锁时的行为差异:

场景 公平锁 (FairSync) 非公平锁 (NonfairSync)
锁空闲时 先检查队列是否有等待者 有则排队,无则尝试CAS 直接尝试CAS抢锁
锁被持有时 加入队列末尾等待 直接尝试一次tryAcquire 失败才入队
唤醒后 严格按照队列顺序 新线程可能"插队"抢锁

# 公平锁

公平锁核心:

// FairSync.tryAcquire() 方法的关键部分
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    
    if (c == 0) {  // 锁空闲时
        // ↓↓↓ 公平性的关键检查 ↓↓↓
        if (!hasQueuedPredecessors() &&  // 检查是否有前驱等待者
            compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 重入逻辑与非公平锁相同...
    return false;
}

// 判断队列中是否有前驱等待者
public final boolean hasQueuedPredecessors() {
    Node t = tail;  // 尾节点
    Node h = head;  // 头节点
    Node s;
    
    // 三种情况返回true(表示有前驱等待者):
    // 1. h != t 且 (h.next == null)      -> 有其他线程正在入队
    // 2. h != t 且 s.thread != current  -> 队首不是当前线程
    // 3. h == t                          -> 队列为空(实际上不会执行到这里)
    
    return h != t && 
           ((s = h.next) == null || s.thread != Thread.currentThread());
}

公平锁的公平性依赖于AQS的FIFO等待队列:

  1. 入队顺序:严格按照请求锁的时间顺序
  2. 出队顺序:严格按照入队顺序
  3. 唤醒机制:只唤醒队首线程
// 等待队列结构示意
HEAD → Node(Thread1) → Node(Thread2) → Node(Thread3) → TAIL
   ↑                                    ↑
持有锁的线程                        最新等待的线程

ReentrantLock 默认是非公平锁,因为它允许新来的线程插队尝试 CAS 获取锁,这能利用线程调度的空档期,大幅提升吞吐量。而公平锁严格遵循 FIFO,虽然公平但性能较差。”

ReentrantLock通过hasQueuedPredecessors()方法实现公平性,在获取锁前先检查是否有更早的等待者。这个简单的检查机制确保了"先来先服务"的原则,但以一定的性能开销为代价。

阅读全文
×

(为防止恶意爬虫)
扫码或搜索:HelloCoder
发送:290992
即可永久解锁本站全部文章

解锁
#ReentrantLock#八股文之
上次更新: 2025-12-04 03:34:09
最近更新
01
MySQL支持的锁有哪些
12-04
02
Synchronized相关
12-04
03
synchronized锁升级
12-04
更多文章>
Theme by Vdoing | Copyright © 2020-2025 码农阿雨
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式