ReentrantLock блокировки Java (1)

Java задняя часть

1. Структура ReenTrantLock

Изображение 1-1

Согласно приведенному выше рисунку, ReenTrantLock наследует интерфейс Lock, а метод объявления интерфейса Lock выглядит следующим образом:

имя метода инструкция Выбросить исключение
замок() Он был заблокирован, чтобы получить блокировку, пока не удастся никто
блокироватьпрерывательно() Попытка получить блокировку до тех пор, пока блокировка не будет получена или поток не будет прерван InterruptedException
попытка блокировки () Попытка получить блокировку бездействия, возвращает true, если получение прошло успешно, false, если получение не удалось, не блокируется, возвращается немедленно никто
tryLock(long time, TimeUnit unit) Попытка получить незанятую блокировку в течение времени, которая может быть прервана во время ожидания. InterruptedException
разблокировать () разблокировать замок никто
newCondition() Возвращает экземпляр условия текущей блокировки для условного ожидания никто

2. Класс реализации Lock ReentrantLock

1. Некоторые методы ReentrantLock

Фото 2-1

  • Согласно рисунку 2-1, вы можете знать, что объект синхронизации предоставляет все механизмы реализации, и синхронизация наследует абстрактный udeuedsynchronizer
  • Несправедливая блокировка NonfairSync, унаследованная синхронизация
  • Справедливая синхронизация FairSync, унаследованная синхронизация

1. Sync


Sync является родительским классом для NonfairSync и FairSync, и метод объявления выглядит следующим образом:

      /**
       * 抽象方法,获取锁
       */
      abstract void lock();

      /**
       * 实现非公平锁获取逻辑
       */
      final boolean  nonfairTryAcquire(int acquires) {
          final Thread current = Thread.currentThread();
          int c = getState(); //父类同步器方法,获取当前同步状态,后续文章会分析
          if (c == 0) {//状态等于0表示没有获取到锁
              if (compareAndSetState(0, acquires)) { //CAS方式修改状态
                  setExclusiveOwnerThread(current); //修改成功后设置当前线程为锁的所有者
                  return true;
              }
          }
          else if (current == getExclusiveOwnerThread()) {//当前锁已被占用,判断是不是自己获取到了锁,锁重入
              int nextc = c + acquires; //获取锁的计数器
              if (nextc < 0) // overflow //因为是int类型,如果超过int最大值会溢出为负
                  throw new Error("Maximum lock count exceeded");
              setState(nextc);//设置计数器为状态值
              return true;
          }
          return false;
      }

      protected final boolean tryRelease(int releases) {
          int c = getState() - releases;//释放锁,同步状态减int值
          if (Thread.currentThread() != getExclusiveOwnerThread())
              throw new IllegalMonitorStateException(); //如果当前相差不是锁的拥有者,抛出异常
          boolean free = false;
          if (c == 0) { //如果同步状态值为0,表示锁已经释放成功
              free = true; 
              setExclusiveOwnerThread(null); // 设置锁的拥有线程为null
          }
          setState(c);//重新赋值同步状态
          return free;
      }
      //判断当前线程是不是锁独占
      protected final boolean isHeldExclusively() {
        
          return getExclusiveOwnerThread() == Thread.currentThread();
      }
      //返回锁的ConditionObject实例
      final ConditionObject newCondition() {
          return new ConditionObject();
      }

      // Methods relayed from outer class
      //获取当前占有锁的线程
      final Thread getOwner() {
          return getState() == 0 ? null : getExclusiveOwnerThread();
      }
      //获取当前锁计数
      final int getHoldCount() {
          return isHeldExclusively() ? getState() : 0;
      }
      //判断是否获取到锁
      final boolean isLocked() {
          return getState() != 0; //可以知道判断获取锁的关键就是是否不等于0
      }

2. Несправедливая блокировка NonfairSync


 static final class NonfairSync extends Sync {
       private static final long serialVersionUID = 7316153563782823691L;

       /**
        * Performs lock.  Try immediate barge, backing up to normal
        * acquire on failure.
        */
       final void lock() {
           if (compareAndSetState(0, 1))//CAS获取锁
               setExclusiveOwnerThread(Thread.currentThread());
           else
               acquire(1);
       }

       protected final boolean tryAcquire(int acquires) {
           return nonfairTryAcquire(acquires);
       }
   }
  • Согласно исходному коду, непубличный замок наследует родительский класс синхронизации. Поскольку выпуск блокировки не существует справедливой и несправедливой, общедоступные блокировки и невыполненные замки достигают логики соответствующих замков приобретения. Согласно исходному коду неконфиденциально замка, это только реализуется.lock()иtryAcquire(int acquires)метод, который иtryAcquire(int acquires)Метод напрямую вызывает родительский классnonfairTryAcquire(acquires), Он был проанализирован при представлении родительского класса. Если вы не уверены, см. выше раздел "Синтаксический анализ синхронизации". В соответствии с исходным кодом блокировки он начинает судить, была ли блокировка получена впервые.Если блокировка получена успешно, текущий поток устанавливается в качестве владельца блокировки, в противном случае вызывается родительский класс.acquire(1)Метод (в следующей статье будет представлен синхронизатор).

3. Честная блокировка FairSync


 static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;
        /**调用父类的acquire()方法*/
        final void lock() {
            acquire(1);
        }

        /**
         * 尝试获取锁
         */
        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;
        }
    }
  • В соответствии с приведенным выше кодом я обнаружил, что код получения и код блокировки получения блокировки без полиции очень информативны, а честная блокировка - только одна.!hasQueuedPredecessors()Суждение, на самом деле, этот метод заключается в том, чтобы определить, существует ли поток, ожидающий дольше, чем текущий поток.Если нет, то попытаться получить блокировку и установить текущий поток в качестве владельца блокировки после успешного получения , Таким образом, справедливость и несправедливость зависят от времени.Ожидание, чтобы получить замок, например, еда в столовой, и стоять в очереди один за другим, это справедливо, и если кто-то сокращается в очереди, это несправедливо.

3. ReentrantLock другие методы


 public ReentrantLock() {
        sync = new NonfairSync();
    }
public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
  public void lock() {
        sync.lock();
    }
 public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }
    //指定超时时间内获取锁,阻塞时间为timeout
 public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
 public Condition newCondition() {
        return sync.newCondition();
    }
public int getHoldCount() {
        return sync.getHoldCount();
    }
  public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }
 public final boolean isFair() {
        return sync instanceof FairSync;
    }
protected Thread getOwner() {
        return sync.getOwner();
    }
public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }
  public final boolean hasQueuedThread(Thread thread) {
        return sync.isQueued(thread);
    }
public final int getQueueLength() {
        return sync.getQueueLength();
    }
protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }
 public boolean hasWaiters(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
    }
   public int getWaitQueueLength(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
    }
    protected Collection<Thread> getWaitingThreads(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
    }

  • Фактически, в соответствии с приведенным выше исходным кодом обнаружено, что независимо от того, является ли это методом реализации интерфейса LOCK или методом, недавно добавленным позже, его функция реализации зависит от объекта, то естьsync, во введенииsyncВремя уже сказало, что это передается по наследствуAbstractQueuedSynchronizerСинхронизатор, многие методы являются методами прямого вызова синхронизатора родительского класса, анализу будет посвящена следующая статья "ReentrantLock of java lock (2)"AbstractQueuedSynchronizerИсходный код синхронизатора, проанализируйте, как синхронизатор полагается на очередь FIFO для завершения механизма блокировки.

В-третьих, резюме

  • ReentrantLock реализует интерфейс LOCK
  • ReentrantLock может обеспечить справедливую и нечестную блокировку.
  • ReentrantLock может получать блокировки в течение периода ожидания.
  • ReentrantLock может выполнять условное ожидание и пробуждение.
  • ReentrantLock может получать блокировки в ответ на прерывания