Java鎖之ReentrantLock(一)

1、ReenTrantLock結構

 

圖1-1java

根據上圖能夠知道,ReenTrantLock繼承了Lock接口,Lock接口聲明方法以下:ui

方法名 說明 拋出異常
lock() 一直阻塞獲取鎖,直到獲取成功
lockInterruptibly() 嘗試獲取鎖,直到獲取鎖或者線程被中斷 InterruptedException
tryLock() 嘗試獲取空閒的鎖,獲取成功返回true,獲取失敗返回false,不會阻塞,當即返回
tryLock(long time, TimeUnit unit) 嘗試在time時間內獲取空閒的鎖,在等待時間內能夠被中斷 InterruptedException
unlock() 釋放鎖
newCondition() 返回當前鎖的一個condition實例,用於條件性等待

2、Lock的實現類ReentrantLock

1.ReentrantLock的部分方法spa

 

 

圖2-1線程

  • 根據圖2-1能夠知道 Sync對象提供了全部的實現機制,而Sync繼承了AbstractQueuedSynchronizer
  • NonfairSync 不公平鎖,繼承了Sync
  • FairSync 公平同步,繼承了Sync

1. Sync

Sync是NonfairSync 和FairSync 的父類,聲明方法以下:code

/**
       * 抽象方法,獲取鎖
       */
      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);
       }
   }
複製代碼
  • 根據源碼發現 非公平鎖繼承了Sync父類,因爲鎖的釋放不存在公平與不公平,因此公平鎖和非公平鎖只實現各自獲取鎖的邏輯。根據非公平鎖的源碼發現,其內部只實現了lock()tryAcquire(int acquires)方法,其中和tryAcquire(int acquires)方法直接調用了父類的nonfairTryAcquire(acquires),介紹父類的時候已經解析過,不清楚能夠看上文Sync解析部分。根據lock源碼發現,開始判斷是不是第一次獲取鎖,若是獲取鎖成功,就把當前線程設置爲鎖的佔有者,不然調用父類的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同步器,不少方法都是直接調用父類同步器的方法,下一篇《java鎖之ReentrantLock(二)》會重點解析AbstractQueuedSynchronizer同步器源碼,分析同步器是如何依託於FIFO隊列完成鎖的機制。

3、 總結

  • ReentrantLock實現了LOCK接口
  • ReentrantLock能夠實現公平鎖和非公平鎖獲取
  • ReentrantLock能夠進行超時時間內獲取鎖
  • ReentrantLock能夠進行條件等待和喚醒
  • ReentrantLock能夠獲取鎖響應中斷
相關文章
相關標籤/搜索