ReentrantLock加锁流程

一、ReentrantLock 公平锁加锁流程

  • 首先,根据我们传入的boolean值决定ReentrantLock为公平锁还是非公平锁。(默认为非公平锁)

  • 我们调用lock()方法加锁时,底层实际为调用ReentrantLock持有的Sync对象的acquire(1)方法。

    public void lock() {
         sync.acquire(1);
     }
    
    
  • acquire(1)方法调用tryAcquire(1)方法尝试加锁,失败后调用acquiredQueued(addWaiter(Node.EXECUSIVE),arg)方法将当前线程包装成一个Node节点加入到等待队列

       public final void acquire(int arg) {
         if (!tryAcquire(arg) &&
             acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
             selfInterrupt();
     }
    
  • tryAcquire()方法会首先判断锁是否空闲,如果空闲则用hasQueuePreProcessor()判断自己是否需要排队,如果不需要排队则CAS操作尝试获取锁,获取锁成功,则将持有锁的线程设置为自己。如果需要排队,则返回false,表示用tryAcquire(1)方法尝试获取锁失败,将自己加入到等待队列。

        @ReservedStackAccess
         protected final boolean tryAcquire(int acquires) {
             final Thread current = Thread.currentThread();
             int c = getState();
             //锁空闲
             if (c == 0) {
             //判断自己是否需要排队
                 if (!hasQueuedPredecessors() &&
                     compareAndSetState(0, acquires)) { //不需要排队则用CAS获取锁
                     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;//否则,返回尝试加锁失败
         }
    
  • 如果tryAcquire(1)判断锁非空闲,则看是否为自己持有锁,若为自己持有,则重入。否则返回false,表示尝试获取锁失败,将自己加入到等待队列。(该方法分公平锁实现和非公平锁两种实现)

    //判断自己是否需要排队
      public final boolean hasQueuedPredecessors() {
         Node h, s;
         //如果等待队列的head不为空
         if ((h = head) != null) {
             if ((s = h.next) == null || s.waitStatus > 0) {
                 s = null; // traverse in case of concurrent cancellation
                 for (Node p = tail; p != h && p != null; p = p.prev) {
                     if (p.waitStatus <= 0)
                         s = p;
                 }
             }
             //判断是否有等待着的线程且不是自己
             if (s != null && s.thread != Thread.currentThread())
                 return true;
         }
         //如果head为null,则不需要等待,因为没有等待队列
         return false;
     }
    
  • acquiredQueued(addWaiter(Node.EXECUSIVE),arg)会首先执行addWaiter()方法,该方法比较简单。

    private Node addWaiter(Node mode) {
         Node node = new Node(mode);
       //大体逻辑就是判断等待队列是否为空,如果是空,则初始化之后再将自己插入,否则直接将自己插入队尾
         for (;;) {
             Node oldTail = tail;
             if (oldTail != null) {
                 node.setPrevRelaxed(oldTail);
                 if (compareAndSetTail(oldTail, node)) {
                     oldTail.next = node;
                     return node;
                 }
             } else {
                 initializeSyncQueue();
             }
         }
     }
    
  • 然后再执行acquireQueued方法。首先判读自己是否是head的.next节点,如果是则tryAcquire(1)再次尝试获取锁,如果不是调用park()让自己睡眠。

    final boolean acquireQueued(final Node node, int arg) {
         boolean interrupted = false;
         try {
             for (;;) {
                 final Node p = node.predecessor();
                 if (p == head && tryAcquire(arg)) {
                     setHead(node);
                     p.next = null; // help GC
                     return interrupted;
                 }
                 if (shouldParkAfterFailedAcquire(p, node)) //此处会多自旋一次
                 //因为每个Node节点的waitStatus是系统默认值0,会返回false,自旋一次
                 //即每一次当前节点会把前一个节点的状态改为-1,即SIGNAL状态
                 //为啥不自己改自己呢?因为自己无法更改,如果在park前设置,但无法保证原子性
                     interrupted |= parkAndCheckInterrupt();
             }
         } catch (Throwable t) {
             cancelAcquire(node);
             if (interrupted)
                 selfInterrupt();
             throw t;
         }
     }
    

二、非公平锁加锁流程

非公平锁和公平锁加锁过程最大的不同是tryAcquire(1)方法,非公平锁该方法的实现是调用了nonfairTryAcquire(acquires)。
即lock()—>Sync.acquire(1)---->tryAcquire(1)---->nonfairTryAcquire(acquires)。

@ReservedStackAccess
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            //非公平锁只要判断锁是空闲的,则直接尝试CAS获取锁,而不会判断自己是否需要排队
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

非公平锁如果用tryAcquire(1)获取锁失败,则后面的流程和公平锁一样。

三、流程图

在这里插入图片描述

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值