AQS和ReentrantLock

  1. AQS提供的几个比较关键的 public 方法有

    1. public final void acquire(int arg)

      底层用到了 protected boolean tryAcquire(int arg)final boolean acquireQueued(final Node node, int arg) 方法

    2. public final void acquireInterruptibly(int arg)
      throws InterruptedException

      底层用到了 private void doAcquireInterruptibly(int arg)
      throws InterruptedException
      方法

    3. public final boolean tryAcquireNanos(int arg, long nanosTimeout)
      throws InterruptedException

      底层用到了 private boolean doAcquireNanos(int arg, long nanosTimeout)
      throws InterruptedException
      方法

    4. public final boolean release(int arg)

      底层用到了 protected boolean tryRelease(int arg) 方法

    5. public final void acquireShared(int arg)

      底层用到了 protected int tryAcquireShared(int arg) 方法

    6. public final void acquireSharedInterruptibly(int arg)
      throws InterruptedException

      底层用到了 private void doAcquireSharedInterruptibly(int arg)
      throws InterruptedException
      方法

    7. public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
      throws InterruptedException

      底层用到了 protected int tryAcquireShared(int arg)private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
      throws InterruptedException
      方法

    8. public final boolean releaseShared(int arg)

      底层用到了 protected boolean tryReleaseShared(int arg)private void doReleaseShared() 方法

    这些 public 方法可以按 acquire/release 分,也可以按 shared/不shared 分,而且分为普通版本、可响应interrupt版本、可定时版本(想想ReentrantLock的几种Lock方式底层其实靠的就是这个);

    值得注意的是,这些 public 方法用到的很多底层方法是要靠派生类实现(不实现的话可以理解为不支持),例如 tryAcquire 方法

     protected boolean tryAcquire(int arg) {
         throw new UnsupportedOperationException();
     }
    
  2. 然后看一下 ReentrantLock 和 AQS 相关的部分

    1. 首先它有一个抽象静态内部类派生了 AQS

       abstract static class Sync extends AbstractQueuedSynchronizer {
      
           ...
       }
      
    2. 然后 Sync 类又有两个派生类 NonfairSync 和 FairSync 代表公平锁和非公平锁,它们的区别在于 tryAcquire 方法的具体实现

       static final class NonfairSync extends Sync {
           ...
           protected final boolean tryAcquire(int acquires) {
               return nonfairTryAcquire(acquires);
           }
       }
      
       static final class FairSync extends Sync {
           ...
           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;
                   }
               } else if (current == getExclusiveOwnerThread()) {
                   int nextc = c + acquires;
                   if (nextc < 0)
                       throw new Error("Maximum lock count exceeded");
                   setState(nextc);
                   return true;
               }
      
               return false;
           }
       }
      
    3. 接下来我们顺着 ReentrantLock 的 lock 方法往里看

      1. 在构造函数中决定了sync用公平锁还是非公平锁

         public void lock() {
             sync.acquire(1);
         }
        

        这个函数的说明是这样的

         /**
          * Acquires the lock.
          *
          * <p>Acquires the lock if it is not held by another thread and returns
          * immediately, setting the lock hold count to one.
          *
          * <p>If the current thread already holds the lock then the hold
          * count is incremented by one and the method returns immediately.
          *
          * <p>If the lock is held by another thread then the
          * current thread becomes disabled for thread scheduling
          * purposes and lies dormant until the lock has been acquired,
          * at which time the lock hold count is set to one.
          */
        

        这个说明大概的意思是:如果锁被其他线程占领了会阻塞;否则的话把state这个变量加1

         public abstract class AbstractQueuedSynchronizer extend AbstractOwnableSynchronizer implements java.io.Serializable {
             ...
        
             /**
              * The synchronization state.
              */
             private volatile int state;
        
             ...
         }
        
      2. 然后 acquire 是 AQS 的 final 方法,覆盖不了

         public final void acquire(int arg) {
        
             if (!tryAcquire(arg) &&
                 acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                 selfInterrupt();
         }
        
      3. 然后看 tryAcquire 方法,这个方法被 NonfairSync 和 FairSync 覆盖了,然后 NonfairSync 比较简单,我们就看这个

         static final class NonfairSync extends Sync {
        
             private static final long serialVersionUID = 7316153563782823691L;
        
             protected final boolean tryAcquire(int acquires) {
                 return nonfairTryAcquire(acquires);
             }
         }
        
      4. NonfairSync 的 tryAcquire 方法很简单,它调用的是 Sync 类实现的 nonfairTryAcquire 方法(要牢牢记住获取不到是会阻塞的)

         abstract static class Sync extends AbstractQueuedSynchronizer {
        
             ...
        
             final boolean nonfairTryAcquire(int acquires) {
        
                 final Thread current = Thread.currentThread();  // 获取当前线程
        
                 int c = getState();  // 获取state变量(不需要阻塞,因为它是volatile修饰的)
        
                 // state是0,代表没有加锁,所以用cas操作加1,如果成功就返回成功
                 if (c == 0) {
                     if (compareAndSetState(0, acquires)) {
                         setExclusiveOwnerThread(current);  // 设置{@code exclusiveOwnerThread}这个变量为当前线程,这个变量代表exclusive模式下的所有者线程
                         return true;
                     }
                 }
                 // 如果state不是0,但是所有者线程就是自身的话就让state自增
                 else if (current == getExclusiveOwnerThread()) {
                     int nextc = c + acquires;
                     if (nextc < 0) // overflow
                         throw new Error("Maximum lock count exceeded");
                     setState(nextc);  // 直接写state变量就行,因为其他线程肯定写不了
                     return true;
                 }
        
                 return false;
             }
        
             ...
         }
        

      nonfairTryAcquire 这个方法不会阻塞,所以 NonfairSync 的 tryAcquire 方法不会阻塞,它会立刻返回 true(acquire成功)/false(acquire失败)

      1. 既然 tryAcquire 不会阻塞,那么根据lock方法的语义,说明 acquireQueued 一定会阻塞,acquireQueued 也是 AQS 的 final 方法,它在很多地方都用到了

         final boolean acquireQueued(final Node node, int arg) {
             // interrupted怎么搞的没看懂
             boolean interrupted = false;
        
             try {
                 // 这是个死循环
                 for (;;) {
                     final Node p = node.predecessor();
                     // 当当前结点恰好是头节点的下一个并且tryAcquire成功时,把头节点换成当前结点,并且返回
                     if (p == head && tryAcquire(arg)) {
                         setHead(node);  // 这个也是直接set就行,因为没有竞争
                         p.next = null; // help GC
                         return interrupted;
                     }
                     if (shouldParkAfterFailedAcquire(p, node))
                         interrupted |= parkAndCheckInterrupt();
                 }
             } catch (Throwable t) {
                 cancelAcquire(node);
                 if (interrupted)
                     selfInterrupt();
                 throw t;
             }
         }
        
      2. 这样 lock 方法就看完了,基本思路就是能获取到就立刻返回,不能获取就加上排队队列自旋,for死循环中不断尝试 tryAcquire

    4. 然后看一下 ReentrantLock 的 unlock 方法

       public void unlock() {
           sync.release(1);
       }
      
      1. release 方法是 AQS 的 final 方法

        public final boolean release(int arg) {

         if (tryRelease(arg)) {
             Node h = head;
             if (h != null && h.waitStatus != 0)
                 unparkSuccessor(h);
             return true;
         }
        
         return false;
        

        }

      2. 然后重点是 tryRelease 方法, 这个方法由 Sync 类覆盖

         protected final boolean tryRelease(int releases) {
        
             int c = getState() - releases;
        
             // 判断一下unlock的线程一定是持有锁的线程
             if (Thread.currentThread() != getExclusiveOwnerThread())
                 throw new IllegalMonitorStateException();
        
             boolean free = false;
        
             if (c == 0) {
                 free = true;
                 setExclusiveOwnerThread(null);
             }
        
             setState(c);
             return free;
         }
        

        这个比较容易看懂,基本就是让state自减,直到state为0把exclusive线程置为null。所以unlock是不会阻塞的

  3. 总结一下就是

    1. ReentrantLock 使用的是exclusive模式(非shared),主要覆盖了tryAcquire和tryRelease两个方法(当然也实现了一些其他的)

    2. state用于标识锁的状态,0代表没有被抢占,N(N>1)代表被同一个线程上锁了多少次,unlock的时候会一层一层的减1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值