赏析ReentrantLock源码

公平锁 VS 非公平锁

  • FairSync:按照请求锁的顺序来分配锁
  • NonfairSync:上来直接先请求锁,不按顺序
    这里写图片描述
    这里写图片描述

ReentrantLock

可重入锁,在一个线程中可多次获取到该锁;主要通过AQS实现;通过使用ReentrantLock可以比synchronized更加灵活,ReentrantLock并不是真正的通过同步加锁实现的,性能比synchronized好;

  • 一般情况下ReentrantLock的使用过程

    //先获取锁
    lock.lock();
     try {
         ... //业务逻辑
     } finally{
         //finally块进行锁的释放,保证获取到的锁被释放
         lock.unlock();
     }
     
    
  • AQS通过state属性来控制所状态

    //AQS的静态代码块
    static {
        try {
            //获取到state的offset,供后面的CAS操作用
            stateOffset = unsafe.objectFieldOffset
                (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
            headOffset = unsafe.objectFieldOffset
                (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
            tailOffset = unsafe.objectFieldOffset
                (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
            waitStatusOffset = unsafe.objectFieldOffset
                (Node.class.getDeclaredField("waitStatus"));
            nextOffset = unsafe.objectFieldOffset
                (Node.class.getDeclaredField("next"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    
    
  • 而锁定操作通过CAS操作AQS的state

    //AQS的state属性定义,用volatile修饰(内存可见性保证)
    private volatile int state;
    
    
    //AQS的CAS操作
    protected final boolean compareAndSetState(int expect, int update) {
        //通过unsafe的CAS操作state
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }
    
    

NonfairSync(非公平锁)

  • ReentrantLock默认的锁方式

    public ReentrantLock() {
        sync = new NonfairSync();
    }
    
    
  • 看看ReentrantLock#lock()是如何实现(NonfairLock)

    public void lock() {
        //因为ReentrantLock的默认构造方法把sync初始化为NonfairLock,所以这里的lock是采用非公平锁的lock
        sync.lock();
    }
    
    
  • 接着看NonfairLock#lock()

    final void lock() {
        //非公平锁的lock一来就先获取锁(AQS通过维护state值来实现锁,0表示未锁定)
        //通过CAS来实现,具体看上面的compareAndSetState实现解析
        if (compareAndSetState(0, 1))
            //state状态设置成功,说明可以马上拿到资源,直接将当前的线程设置为锁的独占线程
            //ReentrantLock采用独占锁方式
            //重入的时候会用来比较是否同一个线程
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
        }
    }
    
    
    • acquire(1)调用的是AQS提供的方法
      public final void acquire(int arg) {
          //调用NonfairLock的tryAcquire,
          //NonfairLock的tryAcquire再调用Sync#nonfairTryAcquire获取锁,
          //如果获取到锁,继续执行程;
          //获取不到锁,继续调用AbstractQueuedSynchronizer#acquireQueued,
          //如果有中断操作,对当前线程interrupt
          if (!tryAcquire(arg) &&
              acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
              selfInterrupt();
      }
      
      
    • Sync#nonfairTryAcquire操作
      //传进来的acquires为1
      final boolean nonfairTryAcquire(int acquires) {
          // 获取当前线程对象
          final Thread current = Thread.currentThread();
          // 获取AQS的state
          int c = getState();
          //如果是0表示能获取到锁
          if (c == 0) {
              //通过CAS获取锁
              if (compareAndSetState(0, acquires)) {
                  //获取到锁,将当前线程设置为锁的独占线程,返回true表示获取到锁
                  setExclusiveOwnerThread(current);
                  return true;
              }
          }
          //state不为0(表示已经有线程获取到该锁),
          //那么判断当前线程和持有锁的独占线程是否为同一个线程,
          //同一个线程可以重入
          else if (current == getExclusiveOwnerThread()) {
              //将当前的state加上acquires,这里为1
              int nextc = c + acquires;
              if (nextc < 0) // overflow
                  throw new Error("Maximum lock count exceeded");
              //设置state值,因为state为volatile,所有内存可见
              setState(nextc);
              //返回true,表示获取到锁
              return true;
          }
          return false;
      }
      
      
    • AQS#addWaiter操作
      private Node addWaiter(Node mode) {
          //新建一个node,以当前线程作为Node的thread
          Node node = new Node(Thread.currentThread(), mode);
          Node pred = tail;
          //如果tailNode不为空
          if (pred != null) {
              //将新建的node的prev指向到tail
              node.prev = pred;
              // 通过CAS将新建的node设置为tail
              if (compareAndSetTail(pred, node)) {
                  // 将之前的tailNode的next指向新建的node
                  //结合前面的操作,意思就是将新建的node插入到队尾
                  pred.next = node;
                  return node;
              }
          }
          //如果不能将node插入到队尾,那么就调用AQS#enq
          enq(node);
          return node;
      }
      private final boolean compareAndSetTail(Node expect, Node update) {
          //tailOffset为tailNode的offset,在AQS静态初始化块中初始化的
          return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
      }
      private Node enq(final Node node) {
          //采用自旋的方式将node设置为tail
          for (;;) {
              Node t = tail;
              //如果队尾node为空,那么表示队列里没有node
              if (t == null) { // Must initialize
                  //通过CAS将一个新的node作为head,然后将tail设置成head一样的node,
                  //即队列只有一个元素
                  if (compareAndSetHead(new Node()))
                      tail = head;
              } else {
                  //否则将当前的node设置为队尾
                  node.prev = t;
                  if (compareAndSetTail(t, node)) {
                      t.next = node;
                      return t;
                  }
              }
          }
      }
      
      
    • AbstractQueuedSynchronizer#acquireQueued操作
      final boolean acquireQueued(final Node node, int arg) {
          boolean failed = true;
          try {
              boolean interrupted = false;
              //采用自旋方式,拿锁
              for (;;) {
                  //获取传入node的前一个node
                  final Node p = node.predecessor();
                  //如果前一个node为head node,那么尝试获取锁
                  if (p == head && tryAcquire(arg)) {
                      // 获取到锁以后,将head设置为传入node,并将node的thread和prev设置为null
                      setHead(node);
                      p.next = null; // help GC
                      //failed设置为false,finally中不需要调用cancelAcquire
                      failed = false;
                      //终止状态返回false
                      return interrupted;
                  }
                  // head不为传入的node的前一个node,或者获取不到锁
                  // 调用AQS#shouldParkAfterFailedAcquire和AbstractQueuedSynchronizer#parkAndCheckInterrupt,
                  // 如果中间有被interrupt过,那么interrupted状态为true
                  if (shouldParkAfterFailedAcquire(p, node) &&
                      parkAndCheckInterrupt())
                      interrupted = true;
              }
          } finally {
              if (failed)
                  //通过自旋如果获取锁失败,取消获取锁操作
                  cancelAcquire(node);
          }
      }
      private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
          //获取prev node的等待状态
          int ws = pred.waitStatus;
          if (ws == Node.SIGNAL)
              //如果等待状态SIGNAL,直接返回true
              return true;
          if (ws > 0) {
              //一直找到waitStatus为非CANCEL的节点,
              //并将找到的节点的next设置node,也就是将CANCEL的节点抛弃了
              do {
                  node.prev = pred = pred.prev;
              } while (pred.waitStatus > 0);
              pred.next = node;
          } else {
              // 否则将pred node的状态设置为SIGNAL
              compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
          }
          return false;
      }
      private final boolean parkAndCheckInterrupt() {
          LockSupport.park(this); //调用park()使线程进入waiting状态
          return Thread.interrupted(); //如果被notify,查看自己是不是被中断的
      }
      
      
  • 前面讲的都lock的过程,接下来看看unlock

    • ReentrantLock的unlock方法调用AQS的release方法
      public final boolean release(int arg) {
          if (tryRelease(arg)) {
              Node h = head;
              if (h != null && h.waitStatus != 0)
                  unparkSuccessor(h);
              return true;
          }
          return false;
      }
      
      
      release通过Sync的tryRelease来释放锁方法
      protected final boolean tryRelease(int releases) {
          int c = getState() - releases;
          if (Thread.currentThread() != getExclusiveOwnerThread())
              throw new IllegalMonitorStateException();
          boolean free = false;
          //如果c为0,表示当前锁释放掉以后,不再持有锁,将独占锁线程设置为null
          if (c == 0) {
              //如果锁释放了,且当前线程不持有锁,那么返回true,否则返回false
              free = true;
              setExclusiveOwnerThread(null);
          }
          //设置state为c,如果c大于0,表示c还持有独占锁
          setState(c);
          return free;
      }
      
      

FairSync(公平锁)

想要使用公平锁,则需要在创建ReentrantLock的时候传入参数,new ReentrantLock(true);

  • 公平锁的lock过程:

    final void lock() {
        //直接调用AQS的acquire方法
        acquire(1);
    }
    
    
    //调用基本跟非公平锁类似,只是tryAcquire调用的是FairSync的方法
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    
    
    //只有在1、队列中没有等待锁且锁未被其他线程持有
    //2、或者当前线程为已持有锁的线程时获取锁成功
    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;
    }
    

总结

  • 可重入锁主要采用被声明为volatile的state变量来控制所的获取及释放;
  • 当state为0时,表示没有线程获取锁,大于1时,表示已经有线程获取到锁,而state的数值表示获取锁的线程lock了state次
  • 公平锁和非公平锁的主要区别在于公平锁总是按照先来后到的顺序获取锁,比较死板,性能较差;而非公平锁是线程去争取锁,性能较好
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值