ReentrantLock & ReentrantReadWriteLock -- 源码解析

目录

1. ReentrantLock & ReentrantReadWriteLock使用场景

ReentrantLock 和 synchronized的区别

ReentrantReadWriteLock

锁的大概方法

2. Sync详解

FairSync 

FairSync --- 获取锁

NonFairSync -- 获取锁

3. ReentrantReadWriteLock源码解析

  类属性

 读写状态是如何设计的

基本读写锁结构

写锁的获取和释放

写锁获取

写锁的释放 -- release

读锁的获取和释放

 读锁的获取

读锁的释放


1. ReentrantLock & ReentrantReadWriteLock使用场景

ReentrantLock 和 synchronized的区别

  •  用法不同
    • synchronized 可用来修饰普通方法、静态方法和代码块,而 ReentrantLock 只能用在代码块上。

  • 释放方式不同

    • synchronized可以自己释放锁, ReentrantLock需要手动

  • 底层实现方式不同

    • synchronized作用在JVM上, ReentrantLock是基于java代码实现的

  • 锁类型不同

    • synchronized只支持非公平锁, ReentrantLock支持公平锁 & 非公平锁

  • 响应中断不同

    • ReentrantLock可以支持lockInterruptibly相应中断, 如果有死锁,可以直接报Expection

        

ReentrantReadWriteLock

        现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁。在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源;但是如果一个线程想去写这些共享资源,就不应该允许其他线程对该资源进行读和写的操作了。

锁的大概方法

在这里插入图片描述

 解释, lockInterruptibly , 如果手动调用线程, 把线程interruptibly,那么就会立刻给出中断信息

2. Sync详解

  • 有FairSync 和 NonFairSync

  • FairSync 

  • FairSync --- 获取锁

    • // 尝试获取锁
      protected final boolean tryAcquire(int acquires) {
                  final Thread current = Thread.currentThread();
                  // 获取node节点的状态, 是AQS配合使用的
                  // AQS中用state表示这个锁有没有人获取
                  int c = getState(); 
                  // 0表示没有人获取锁
                  if (c == 0) {
                      // 这个就是公平锁的实现, 去看之前是否有等待的锁
                      if (!hasQueuedPredecessors() &&
                          // 设置状态, 把state设置成获取多少的数(上游传递保证冲入等)
                          compareAndSetState(0, acquires)) {
                          // 设置目前占用这个锁的线程是什么
                          setExclusiveOwnerThread(current);
                          return true;
                      }
                  }
                  // 当状态不是0的时候,说明是有人
                  // 看下现在独占这个锁的线程, 如果是本线程,那么就是重入锁的设置
                  else if (current == getExclusiveOwnerThread()) {
                      int nextc = c + acquires;
                      if (nextc < 0)
                          throw new Error("Maximum lock count exceeded");
                      setState(nextc);
                      return true;
                  }
                  return false;
              }
      
          // AQS中的方法,之前是否有节点在等待锁
          public final boolean hasQueuedPredecessors() {
              // The correctness of this depends on head being initialized
              // before tail and on head.next being accurate if the current
              // thread is first in queue.
              Node t = tail; // Read fields in reverse initialization order
              Node h = head;
              Node s;
              return h != t &&
                  ((s = h.next) == null || s.thread != Thread.currentThread());
          }
  • NonFairSync -- 获取锁

    • final void lock() {
                  // 设置状态, 如果状态成功,那么说明就可以获取到锁
                  if (compareAndSetState(0, 1))
                      setExclusiveOwnerThread(Thread.currentThread());
                  else
                      // AQS中的方法, 会调用下面的nonfairTryAcquire
                      acquire(1);
              }
      
              protected final boolean tryAcquire(int acquires) {
                  return nonfairTryAcquire(acquires);
              }
      
      
      // 非公平获取锁
      final boolean nonfairTryAcquire(int acquires) {
                  final Thread current = Thread.currentThread();
                  int c = getState();
                  // 如果没有人有锁
                  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;
              }

3. ReentrantReadWriteLock源码解析

  •   类属性

    • bstract static class Sync extends AbstractQueuedSynchronizer {
          // 版本序列号
          private static final long serialVersionUID = 6317671515068378041L;        
          // 高16位为读锁,低16位为写锁
          static final int SHARED_SHIFT   = 16;
          // 读锁单位
          static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
          // 读锁最大数量
          static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
          // 写锁最大数量
          static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
          // 本地线程计数器
          private transient ThreadLocalHoldCounter readHolds;
          // 缓存的计数器
          private transient HoldCounter cachedHoldCounter;
          // 第一个读线程
          private transient Thread firstReader = null;
          // 第一个读线程的计数
          private transient int firstReaderHoldCount;
      }
  •  读写状态是如何设计的

    • 将AQS中的state字段 (线程状态字段, 分成了高16位和低16位)用一个整形,维护了读锁和写锁
    • 读写锁对于同步状态的实现是在一个整形变量上通过“按位切割使用”:将变量切割成两部分,高16位表示读,低16位表示写。
    • 那么如何判断是否持有了写锁 / 读锁
      • 用state >> 16获取 高位16读  低位16写
  • 基本读写锁结构

    • // 读锁标志
      private final ReentrantReadWriteLock.ReadLock readerLock;
      // 写锁标志
      private final ReentrantReadWriteLock.WriteLock writerLock;
      
      public static class ReadLock implements Lock, java.io.Serializable {
              private static final long serialVersionUID = -5992448646407690164L;
              private final Sync sync;
      
            
              protected ReadLock(ReentrantReadWriteLock lock) {
                  sync = lock.sync;
              }
      
              // 获取锁,
              public void lock() {
                  sync.acquireShared(1);
              }
              
              // 建立一个可以被中断的锁
              public void lockInterruptibly() throws InterruptedException {
                  sync.acquireSharedInterruptibly(1);
              }
             
              // 会立刻返回结果,不会等待
              public boolean tryLock() {
                  return sync.tryReadLock();
              }
      
             
              public boolean tryLock(long timeout, TimeUnit unit)
                      throws InterruptedException {
                  return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
              }
              // 释放锁
              public void unlock() {
                  sync.releaseShared(1);
              }
          }
      
      
      // 写锁
      public static class WriteLock implements Lock, java.io.Serializable {
              private static final long serialVersionUID = -4992448646407690164L;
              private final Sync sync;
      
             
              protected WriteLock(ReentrantReadWriteLock lock) {
                  sync = lock.sync;
              }
      
              public void lock() {
                  sync.acquire(1);
              }
      
              public void lockInterruptibly() throws InterruptedException {
                  sync.acquireInterruptibly(1);
              }
      
              public boolean tryLock( ) {
                  return sync.tryWriteLock();
              }
      
              public boolean tryLock(long timeout, TimeUnit unit)
                      throws InterruptedException {
                  return sync.tryAcquireNanos(1, unit.toNanos(timeout));
              }
      
            
              public void unlock() {
                  sync.release(1);
              }
      
            
          }
  •  代码所示
    • 读锁 : acquireShared  acquireSharedInterruptibly. releaseShared
    • 写锁 :    acquire.   acquireInterruptibly.  release
  • 写锁的获取和释放

    • 写锁获取

      • protected final boolean tryAcquire(int acquires) {
                    // 获取当前线程    
                    Thread current = Thread.currentThread();
                    
                    int c = getState();
                    // 获取写锁个数
                    int w = exclusiveCount(c);
                    // 状态是不可以获取
                    if (c != 0) {
                        // (Note: if c != 0 and w == 0 then shared count != 0)
                        // 查看冲入
                        if (w == 0 || current != getExclusiveOwnerThread())
                            return false;
                        // 冲入不能超过16位
                        if (w + exclusiveCount(acquires) > MAX_COUNT)
                            throw new Error("Maximum lock count exceeded");
                        // 设置状态
                        setState(c + acquires);
                        return true;
                    }
                    // 可以获取锁
                    if (writerShouldBlock() ||
                        !compareAndSetState(c, c + acquires))
                        return false;
                    // 设置当前获取到锁的线程
                    setExclusiveOwnerThread(current);
                    return true;
                }
        
        // 非公平锁。永远都可以获取
         final boolean writerShouldBlock() {
                    return false; // writers can always barge
                }
        // 是否前面有等待的节点   fairSync
        final boolean writerShouldBlock() {
                    return hasQueuedPredecessors();
                }
  • 写锁的释放 -- 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;
          }
      
         protected final boolean tryRelease(int releases) {
                  // 如果释放锁的不是ownerThread设置的线程, 直接gg
                  if (!isHeldExclusively())
                      throw new IllegalMonitorStateException();
                  int nextc = getState() - releases;
                  // 如果重入的状态已经是0了
                  boolean free = exclusiveCount(nextc) == 0;
                  // 释放锁
                  if (free)
                      setExclusiveOwnerThread(null);
                  setState(nextc);
                  return free;
              }

    • 读锁的获取和释放

      •  读锁的获取

        •  protected final int tryAcquireShared(int unused) {
                      Thread current = Thread.currentThread();
                      int c = getState();
                      // 如果独占锁的数目大于0, 并且不是当前线程 ,有线程占有了锁
                      if (exclusiveCount(c) != 0 &&
                          getExclusiveOwnerThread() != current)
                          return -1;
                      int r = sharedCount(c);
                      // 读锁是不是需要等待
                      if (!readerShouldBlock() &&
                          r < MAX_COUNT &&
                          compareAndSetState(c, c + SHARED_UNIT)) {
                          if (r == 0) {
                              // 如果能获取读锁了, 那么就设置一下当前的count
                              firstReader = current;
                              firstReaderHoldCount = 1;
                          } else if (firstReader == current) {
                              firstReaderHoldCount++;
                          } else {
                              HoldCounter rh = cachedHoldCounter;
                              if (rh == null || rh.tid != getThreadId(current))
                                  cachedHoldCounter = rh = readHolds.get();
                              else if (rh.count == 0)
                                  readHolds.set(rh);
                              rh.count++;
                          }
                          return 1;
                      }
                      return fullTryAcquireShared(current);
                  }
          
          
          // 说明:在tryAcquireShared函数中,如果下列三个条件不满足(读线程是否应该被阻塞、小于最大值、比较设置成功)则会进行fullTryAcquireShared函数中,它用来保证相关操作可以成功。其逻辑与tryAcquireShared逻辑类似,不再累赘。
          final int fullTryAcquireShared(Thread current) {
             
                      HoldCounter rh = null;
                      for (;;) {
                          int c = getState();
                          // 写锁的个数
                          if (exclusiveCount(c) != 0) {
                              if (getExclusiveOwnerThread() != current)
                                  return -1;
                          // 读锁是否应该block, 和公平 & 非公平锁有关系
                          } else if (readerShouldBlock()) {
                              if (firstReader == current) {
                                  // assert firstReaderHoldCount > 0;
                              } else {
                                  if (rh == null) {
                                      rh = cachedHoldCounter;
                                      if (rh == null || rh.tid != getThreadId(current)) {
                                          rh = readHolds.get();
                                          if (rh.count == 0)
                                              readHolds.remove();
                                      }
                                  }
                                  if (rh.count == 0)
                                      return -1;
                              }
                          }
                          if (sharedCount(c) == MAX_COUNT)
                              throw new Error("Maximum lock count exceeded");
                          if (compareAndSetState(c, c + SHARED_UNIT)) {
                              if (sharedCount(c) == 0) {
                                  firstReader = current;
                                  firstReaderHoldCount = 1;
                              } else if (firstReader == current) {
                                  firstReaderHoldCount++;
                              } else {
                                  if (rh == null)
                                      rh = cachedHoldCounter;
                                  if (rh == null || rh.tid != getThreadId(current))
                                      rh = readHolds.get();
                                  else if (rh.count == 0)
                                      readHolds.set(rh);
                                  rh.count++;
                                  cachedHoldCounter = rh; // cache for release
                              }
                              return 1;
                          }
                      }
                  }
          
          
          // 当前获取的节点, 头节点是不是共享readerShouldBlock 的非公平实现
          final boolean apparentlyFirstQueuedIsExclusive() { 
                  Node h, s;
                  return (h = head) != null &&
                      (s = h.next)  != null &&
                      !s.isShared()         &&
                      s.thread != null;
              }

      • 读锁的释放

        •     
              public final boolean releaseShared(int arg) {
                  if (tryReleaseShared(arg)) {
                      doReleaseShared();
                      return true;
                  }
                  return false;
              }
          
              // 尝试释放读锁
             protected final boolean tryReleaseShared(int unused) {
              // 获取当前线程
              Thread current = Thread.currentThread();
              if (firstReader == current) { // 当前线程为第一个读线程
                  // assert firstReaderHoldCount > 0;
                  if (firstReaderHoldCount == 1) // 读线程占用的资源数为1
                      firstReader = null;
                  else // 减少占用的资源
                      firstReaderHoldCount--;
              } else { // 当前线程不为第一个读线程
                  // 获取缓存的计数器
                  HoldCounter rh = cachedHoldCounter;
                  // 计数器为空或者计数器的tid不为当前正在运行的线程的tid
                  if (rh == null || rh.tid != getThreadId(current)) 
                      // 获取当前线程对应的计数器
                      rh = readHolds.get();
                  // 获取计数
                  int count = rh.count;
                  if (count <= 1) { // 计数小于等于1
                      // 移除
                      readHolds.remove();
                      if (count <= 0) // 计数小于等于0,抛出异常
                          throw unmatchedUnlockException();
                  }
                  // 减少计数
                  --rh.count;
              }
              for (;;) { // 无限循环
                  // 获取状态
                  int c = getState();
                  // 获取状态
                  int nextc = c - SHARED_UNIT;
                  if (compareAndSetState(c, nextc)) // 比较并进行设置
                      // Releasing the read lock has no effect on readers,
                      // but it may allow waiting writers to proceed if
                      // both read and write locks are now free.
                      return nextc == 0;
              }
          }
          
          // 这个是每个线程进来, 都想去获取锁, 然后通过setHeadAndPropagate每次获取到读锁之后,都会更新head,这样的话, 就是acquire和release方法配合使用,风暴遍历,把后面的读线程都唤醒
          private void doAcquireShared(int arg) {
                  final Node node = addWaiter(Node.SHARED);
                  boolean failed = true;
                  try {
                      boolean interrupted = false;
                      for (;;) {
                          // 找前面的节点
                          final Node p = node.predecessor();
                          if (p == head) {
                              // 释放锁
                              int r = tryAcquireShared(arg);
                              if (r >= 0) {
                                  // 设置头,保证上面的
                                  setHeadAndPropagate(node, r);
                                  p.next = null; // help GC
                                  if (interrupted)
                                      selfInterrupt();
                                  failed = false;
                                  return;
                              }
                          }
                          if (shouldParkAfterFailedAcquire(p, node) &&
                              parkAndCheckInterrupt())
                              interrupted = true;
                      }
                  } finally {
                      if (failed)
                          cancelAcquire(node);
                  }
              }
          
              private void doReleaseShared() {
                  
                  for (;;) {
                      Node h = head;
                      if (h != null && h != tail) {
                          int ws = h.waitStatus;
          //在队列中的节点对应的线程阻塞之前,将前驱节点的waitStatus状态设置为SIGNAL
                      //所以这块ws==0,其实是当前线程通过第一次循环将状态设置为了0,
                      //第二次循环进入的时候头节点还没有被改变
                      //cas操作失败的话会直接continue,为什么会失败,
                      //可能是唤醒得其他节点在唤醒后续节点的时候已经进行了修改
                      //修改失败则代表头节点已经修改,则进入下一次循环
                          if (ws == Node.SIGNAL) {
                              if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                                  continue;            // loop to recheck cases
                              unparkSuccessor(h);
                          }
                          else if (ws == 0 &&
                                   !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                              continue;                // loop on failed CAS
                      }
                      if (h == head)                   // loop if head changed
                          break;
                  }
              }

          所以流程是

          读锁是每次都在唤醒的 

        • 调用上面的tryAcquired的时候 会在循环调用 setHeadAndPropagate ,在这个方法里面,会不断的去设置队列的head, 然后在h==head的时候,就不会结束,就会唤醒下一个节点

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值