ReentrantLock底层原理

JDK版本:jdk11

公平锁和非公平锁

从构造方法可以可看出,ReentrantLock默认为非公平锁,也可以通过有参构造,根据传入的布尔值构造公平锁或非公平锁。
在这里插入图片描述

执行过程

在这里插入图片描述

AQS队列

在这里插入图片描述

Lock底层原理

1,lock( )

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

//lock方法接着调用了AbstractQueuedSynchronizer的acquire()方法。
public final void acquire(int arg) {
    if (!tryAcquire(arg) && //先尝设置独占线程
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //如果设置失败,放入队列
        selfInterrupt();
}

2,tryAcquire(int arg)

//非公平锁
 @ReservedStackAccess
 final boolean nonfairTryAcquire(int acquires) {
     final Thread current = Thread.currentThread();
     int c = getState();  //获取锁的状态,state=0说明当先没有线程获取锁
     if (c == 0) {
         if (compareAndSetState(0, acquires)) { //通过CAS设置state
             setExclusiveOwnerThread(current); //设置独占线程
             return true;
         }
     }
     else if (current == getExclusiveOwnerThread()) { //查看占有锁的线程是不是当前线程
         int nextc = c + acquires; //如果是,state+1(可重入锁)
         if (nextc < 0) // overflow
             throw new Error("Maximum lock count exceeded");
         setState(nextc);
         return true;
     }
     return false;
 }


//公平锁
 @ReservedStackAccess
  protected final boolean tryAcquire(int acquires) {
      final Thread current = Thread.currentThread();
      int c = getState();
      if (c == 0) {
          if (!hasQueuedPredecessors() &&  //公平锁的非公平锁的主要区别就在这里
          //公平锁会查看是否有AQS队列,如果有,会让其他线程去排队,不会和队列中的线程竞争锁
              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;
   }


 public final boolean hasQueuedPredecessors() {
     Node h, s;
     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;
     }
     return false;
 }

3,addWaiter(Node mode)

//在调用acquireQueued()方法前,会先调用addWaiter()方法
//此方法就是判断AQS队列中的Node链表有没有初始化,如果没有先初始化链表,有就把新的Node节点放在链表尾部。
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();
         }
     }
 }

4,acquireQueued(final Node node, int arg)

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)) 
                //通过LockSupport.park(this),阻塞当前线程
                interrupted |= parkAndCheckInterrupt();
        }
    } catch (Throwable t) {
        cancelAcquire(node);
        if (interrupted)
            selfInterrupt();
        throw t;
    }
}

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
     int ws = pred.waitStatus;
     if (ws == Node.SIGNAL)
         /*
          * This node has already set status asking a release
          * to signal it, so it can safely park.
          */
         return true;
     if (ws > 0) {
         //waitStatus大于0是取消状态,这些节点直接舍弃
         do {
             node.prev = pred = pred.prev;
         } while (pred.waitStatus > 0);
         pred.next = node;
     } else {
         //把Node的前一个节点设置成-1
         pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
     }
     return false;
 }

UnLock底层原理

unlock()

 public void unlock() {
      sync.release(1);
  }

 public final boolean release(int arg) {
      if (tryRelease(arg)) { //解锁
          Node h = head;
          if (h != null && h.waitStatus != 0)
              unparkSuccessor(h); //唤醒队列中的下一个线程
          return true;
      }
      return false;
  }

//tryRelease方法
@ReservedStackAccess
protected final boolean tryRelease(int releases) {
    int c = getState() - releases; //调用一次tryRelease方法state减1一次 ,直到等于0
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null); //设置独占线程为空
    }
    setState(c);
    return free;
}


unparkSuccessor(Node node)

 private void unparkSuccessor(Node node) {
       
        int ws = node.waitStatus;
        if (ws < 0)
            /**
             * 这里把头节点的waitStatus设置为0,并不会影响队列中其他线程的唤醒,
             * 要结合acquireQueued(final Node node, int arg)方法来看
             */
            node.compareAndSetWaitStatus(ws, 0); 
     
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node p = tail; p != node && p != null; p = p.prev)
                if (p.waitStatus <= 0)
                    s = p;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }


通过 LockSupport.unpark(s.thread) 唤醒下一个线程后,线程会在之前被阻塞的地方继续执行,也就是如下图所示的地方
在这里插入图片描述

然后通过for循环自旋,判断如果自己的pre节点是头节点,那么会把自己设置成新的头节点,而新的头节点waitStatus依然是-1(除Tail节点之外),所以并不会影响队列中其他线程的唤醒。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值