V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
HowieWang
V2EX  ›  Java

Java ReentrantLock 冗余设计?

  •  
  •   HowieWang · 6 小时 54 分钟前 · 878 次点击

    背景

    偶然看到了一篇 ReentrantLock 的源码分析文章,自己便去学习了一下源码。 核心思想是如果被请求的共享资源空闲,那么就将当前请求资源的线程设置为有效的工作线程,将共享资源设置为锁定状态;如果共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁分配。

    问题

    ReentrantLock 的 lock 方法在入队之前直接获取锁,是否冗余设计,存在冗余的代码执行?

    我的观点

    进行了冗余设计,理解如下。

    jdk8

    lock 简化代码如下,我的观点是:非公平锁(NofairSync) lock 方法,有两次尝试直接获取锁,是否冗余设计了?

    static final class NonfairSync extends Sync {
      final void lock() {
        // 直接尝试获取锁,不公平表现
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1); // acquire 方法中首先会调用 tryAcquire ,会第二次尝试获取锁
      }
    
      protected final boolean tryAcquire(int acquires) {
        // 如果资源空闲,直接尝试获取锁
        // 如果资源不空闲,判断是否当前线程占有,进行重入锁
      }
    }
    
    static final class FairSync extends Sync {
      final void lock() {
          acquire(1);
      }
    
      protected final boolean tryAcquire(int acquires) {
        // 如果资源空闲,判断是否已经入队,进行公平处理
        // 如果资源不空闲,判断是否当前线程占有,进行重入锁
      }
    }
    
    class AbstractQueuedSynchronizer {
      public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
      }
    }
    

    jdk17

    lock 简化代码如下,我的观点是:lock 方法,有两次尝试直接获取锁,是否冗余设计了?对于公平锁,均会判断当前线程是否已经入队,是冗余的尝试;对于非公平锁,连续两次尝试直接获取锁,也是冗余的尝试

    abstract static class Sync extends AbstractQueuedSynchronizer {
    
        abstract boolean initialTryLock();
    
        final void lock() {
            if (!initialTryLock()) // 首次尝试获取锁
                acquire(1); // acquire 方法中首先会调用 tryAcquire ,会第二次尝试获取锁
        }
    }
    
    static final class NonfairSync extends Sync {
      final boolean initialTryLock() {
        // 如果资源空闲,直接尝试获取锁
        // 如果资源不空闲,判断是否当前线程占有,进行重入锁
      }
    
      protected final boolean tryAcquire(int acquires) {
        // 如果资源空闲,直接尝试获取锁
      }
    }
    
    static final class FairSync extends Sync {
      final boolean initialTryLock() {
        // 如果资源空闲,判断是否已经入队,进行公平处理
        // 如果资源不空闲,判断是否当前线程占有,进行重入锁
      }
    
      protected final boolean tryAcquire(int acquires) {
        // 如果资源空闲,判断是否已经入队,进行公平处理
      }
    }
    

    我认为的不冗余的方式

    static class Sync extends AbstractQueuedSynchronizer {
      final void lock() {
        acquire(1);
      }
    }
    
    static final class NonfairSync extends Sync {
    
      protected final boolean tryAcquire(int acquires) {
        // 如果资源空闲,直接尝试获取锁
        // 如果资源不空闲,判断是否当前线程占有,进行重入锁
      }
    }
    
    static final class FairSync extends Sync {
    
      protected final boolean tryAcquire(int acquires) {
        // 如果资源空闲,判断是否已经入队,进行公平处理
        // 如果资源不空闲,判断是否当前线程占有,进行重入锁
      }
    }
    
    5 条回复    2025-03-10 16:19:40 +08:00
    herm2s
        1
    herm2s  
       4 小时 36 分钟前   ❤️ 1
    不算设计冗余,两次调用 compareAndSetState 都是为了在无竞争时快速成功。第一次调用返回 false 意味着有竞争,此时进入 acquire 。在 acquire 里会根据 state 的值判断是否调用 compareAndSetState ,原因是这中间有可能从有竞争变为无竞争( volatile ),此时快速成功就行了。state 的值>0 才是可重入锁/其它线程占用的情况,最后再做其它处理。
    Rickkkkkkk
        2
    Rickkkkkkk  
       4 小时 33 分钟前
    你的疑问算是一个面试题了
    kandaakihito
        3
    kandaakihito  
       3 小时 41 分钟前
    经典面试题。跟一楼说的一样,大部分时候资源是不上锁的,一般能快速拿到锁就拉倒了没必要再去 AQS 里面拐一圈。
    这也算是并发编程里面的“快慢路径”的一种体现。
    mamumu
        4
    mamumu  
       3 小时 34 分钟前
    学到了
    JoJoWuBeHumble
        5
    JoJoWuBeHumble  
       3 小时 9 分钟前
    其实把你的问题直接问 AI ,都有答案了。
    1. 非公平锁的“两次尝试”设计
    在非公平锁中,lock() 方法在入队前先尝试直接获取锁(通过 initialTryLock() 或 CAS 操作),若失败再调用 acquire(),而在 acquire() 中又会调用 tryAcquire() 再次尝试。这看似重复,实为优化:

    减少线程挂起/唤醒的开销:当锁被释放时,新线程可能直接抢占锁(插队),而无需等待队列中的线程被唤醒,提高了吞吐量。
    避免不必要的队列操作:若首次尝试成功,线程直接获取锁,无需进入队列,减少了入队、出队和上下文切换的开销。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3360 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 11:28 · PVG 19:28 · LAX 04:28 · JFK 07:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.