国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

Java中同步機制的底層原理是什么

發(fā)布時(shí)間:2021-07-03 23:03 來(lái)源:億速云 閱讀:0 作者:Leah 欄目: 開(kāi)發(fā)技術(shù)

Java中同步機制的底層原理是什么,針對這個(gè)問(wèn)題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。

同步機制源碼初探

ReentrantLock是我們常用的一種可重入互斥鎖,是synchronized關(guān)鍵字的一個(gè)很好的替代品?;コ庵傅木褪峭粫r(shí)間只能有一個(gè)線(xiàn)程獲取到這個(gè)鎖,而可重入是指如果一個(gè)線(xiàn)程再次獲取一個(gè)它已經(jīng)持有的互斥鎖,那么仍然會(huì )成功。

這個(gè)類(lèi)的源碼在JDK的java.util.concurrent包下,我們可以在IDE中點(diǎn)擊類(lèi)名跳轉到具體的類(lèi)定義,比如下面就是在我的電腦上跳轉之后看到的ReentrantLock類(lèi)的源代碼。在這里我們可以看到在ReentrantLock類(lèi)中還包含了一個(gè)繼承自AbstractQueuedSynchronizer類(lèi)的內部類(lèi),而且有一個(gè)該內部類(lèi)Sync類(lèi)型的字段sync。實(shí)際上ReentrantLock類(lèi)就是通過(guò)這個(gè)內部類(lèi)對象來(lái)實(shí)現線(xiàn)程同步的。

如果打開(kāi)CountDownLatch的源代碼,我們會(huì )發(fā)現這個(gè)類(lèi)里也同樣有一個(gè)繼承自AbstractQueuedSynchronizer類(lèi)的子類(lèi)Sync,并且也有一個(gè)Sync類(lèi)型的字段sync。在java.util.concurrent包下的大多數同步工具類(lèi)的底層都是通過(guò)在內部定義一個(gè)AbstractQueuedSynchronizer類(lèi)的子類(lèi)來(lái)實(shí)現的,包括我們在本文中沒(méi)提到的許多其他常用類(lèi)也是如此,比如:讀寫(xiě)鎖ReentrantReadWriteLock、信號量Semaphore等。

AQS是什么?

那么這個(gè)AbstractQueuedSynchronizer類(lèi)也就是我們所說(shuō)的AQS,到底是何方神圣呢?這個(gè)類(lèi)首先像我們上面提到的,是大多數多線(xiàn)程同步工具類(lèi)的基礎。它內部包含了一個(gè)對同步器的等待隊列,其中包含了所有在等待獲取同步器的線(xiàn)程,在這個(gè)等待隊列中的線(xiàn)程將會(huì )在同步器釋放時(shí)被喚醒。比如一個(gè)線(xiàn)程在獲取互斥鎖失敗時(shí)就會(huì )被放入到等待隊列中等待被喚醒,這也就是AQS中的Q——“Queued”的由來(lái)。

而類(lèi)名中的***個(gè)單詞Abstract是因為AQS是一個(gè)抽象類(lèi),它的使用方法就是實(shí)現繼承它的子類(lèi),然后使用這個(gè)子類(lèi)類(lèi)型的對象。在這個(gè)子類(lèi)中我們會(huì )通過(guò)重寫(xiě)下列的五個(gè)方法中的一部分或者全部來(lái)指定這個(gè)同步器的行為策略:

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術(shù)社區

  2.  boolean tryAcquire(int arg),獨占式獲取同步器,獨占式指同一時(shí)間只能有一個(gè)線(xiàn)程獲取到同步器;

  3.  boolean tryRelease(int arg),獨占式釋放同步器;

  4.  boolean isHeldExclusively(),同步器是否被當前線(xiàn)程獨占式地持有;

  5.  int tryAcquireShared(int arg),共享式獲取同步器,共享式指的是同一時(shí)間可能有多個(gè)線(xiàn)程同時(shí)獲取到同步器,但是可能會(huì )有數量的限制;

  6.  boolean tryReleaseShared(int arg),共享式釋放同步器。

這五個(gè)方法之所以能指定同步器的行為,則是因為AQS中的其他方法就是通過(guò)對這五個(gè)方法的調用來(lái)實(shí)現的。比如在下面的acquire方法中就調用了tryAcquire來(lái)獲取同步器,并且在被調用的acquireQueued方法內部也是通過(guò)tryAcquire方法來(lái)循環(huán)嘗試獲取同步器的。

public final void acquire(int arg) {      // 1. 調用tryAcquire方法嘗試獲取鎖      // 2. 如果獲取失敗(tryAcquire返回false),則調用addWaiter方法將當前線(xiàn)程保存到等待隊列中      // 3. 之后調用acquireQueued方法來(lái)循環(huán)執行“獲取同步器 -> 獲取失敗休眠 -> 被喚醒重新獲取”過(guò)程      //      直到成功獲取到同步器返回false;或者被中斷返回true      if (!tryAcquire(arg) &&          acquireQueued(addWaiter(Node.EXCLUSIVE), arg))          // 如果acquireQueued方法返回true說(shuō)明線(xiàn)程被中斷了          //   所以調用selfInterrupt方法中斷當前線(xiàn)程          selfInterrupt();  }

下面,我們就來(lái)看看在ReentrantLock和CountDownLatch兩個(gè)類(lèi)中定義的AQS子類(lèi)到底是如何重寫(xiě)這五個(gè)方法的。

CountDownLatch的實(shí)現

CountDownLatch是一種典型的閉鎖,比如我需要使用四個(gè)線(xiàn)程完成四種不同的計算,然后把四個(gè)線(xiàn)程的計算結果相加后返回,這種情況下主線(xiàn)程就需要等待四個(gè)完成不同任務(wù)的工作線(xiàn)程完成之后才能繼續執行。那么我們就可以創(chuàng )建一個(gè)初始的count值為4的CountDownLatch,然后在每個(gè)工作線(xiàn)程完成任務(wù)時(shí)都對這個(gè)CountDownLatch執行一個(gè)countDown操作,這樣CountDownLatch中的count值就會(huì )減1。當count值減到0時(shí),主線(xiàn)程就會(huì )從阻塞中恢復,然后將四個(gè)任務(wù)的結果相加后返回。

下面是CountDownLath的幾個(gè)常用方法:

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術(shù)社區

  2.  void await(),等待操作,如果count值目前已經(jīng)是0了,那么就直接返回;否則就進(jìn)入阻塞狀態(tài),等待count值變?yōu)?;

  3.  void countDown(),減少計數操作,會(huì )讓count減1。

調用多次countDown()方法讓count值變?yōu)?之后,被await()方法阻塞的線(xiàn)程就可以繼續執行了。了解了CountDownLatch的基本用法之后我們就來(lái)看看這個(gè)閉鎖到底是怎么實(shí)現的,首先,我們來(lái)看一下CountDownLatch中AQS的子類(lèi),內部類(lèi)Sync的定義。

CountDownLatch的內部Sync類(lèi)

下面的代碼是CountDownLatch中AQS的子類(lèi)Sync的定義,Sync是CountDownLatch類(lèi)中的一個(gè)內部類(lèi)。在這個(gè)類(lèi)中重寫(xiě)了AQS的tryAcquireShared和tryReleaseShared兩個(gè)方法,這兩個(gè)都是共享模式需要重寫(xiě)的方法,因為CountDownLatch在count值為0時(shí)可以被任意多個(gè)線(xiàn)程同時(shí)獲取成功,所以應該實(shí)現共享模式的方法。

在CountDownLatch的Sync中使用了AQS的state值用來(lái)存放count值,在初始化時(shí)會(huì )把state值初始化為n。然后在調用tryReleaseShared時(shí)會(huì )將count值減1,但是因為這個(gè)方法可能會(huì )被多個(gè)線(xiàn)程同時(shí)調用,所以要用CAS操作保證更新操作的原子性,就像我們用AtomicInteger一樣。在CAS失敗時(shí)我們需要通過(guò)重試來(lái)保證把state減1,如果CAS成功時(shí),即使有許多線(xiàn)程同時(shí)執行這個(gè)操作***的結果也一定是正確的。在這里,tryReleaseShared方法的返回值表示這個(gè)釋放操作是否可以讓等待中的線(xiàn)程成功獲取同步器,所以只有在count為0時(shí)才能返回true。

tryAcquireShared方法就比較簡(jiǎn)單了,直接返回state是否等于0即可,因為只有在CountDownLatch中的count值為0時(shí)所有希望獲取同步器的線(xiàn)程才能獲取成功并繼續執行。如果count不為0,那么線(xiàn)程就需要進(jìn)入阻塞狀態(tài),等到count值變?yōu)?才能繼續執行。

private static final class Sync extends AbstractQueuedSynchronizer {      private static final long serialVersionUID = 4982264981922014374L;      // 構造器,初始化count值      // 在這個(gè)子類(lèi)中把count值保存到了AQS的state中      Sync(int count) {          setState(count);      }      // 獲取當前的count值      int getCount() {          return getState();      }      // 獲取操作在state為0時(shí)會(huì )成功,否則失敗      // tryAcquireShared失敗時(shí),線(xiàn)程會(huì )進(jìn)入阻塞狀態(tài)等待獲取成功      protected int tryAcquireShared(int acquires) {          return (getState() == 0) ? 1 : -1;      }      // 對閉鎖執行釋放操作減小計數值      protected boolean tryReleaseShared(int releases) {          // 減小coun值,在count值歸零時(shí)喚醒等待的線(xiàn)程          for (;;) {              int c = getState();              // 如果計數已經(jīng)歸零,則直接釋放失敗              if (c == 0)                  return false;              // 將計數值減1              int nextc = c-1;              // 為了線(xiàn)程安全,以CAS循環(huán)嘗試更新              if (compareAndSetState(c, nextc))                  return nextc == 0;          }      }  }

CounDownLatch對Sync類(lèi)對象的使用

看了CountDownLatch中的Sync內部類(lèi)定義之后,我們再來(lái)看看CountDownLatch是如何使用這個(gè)內部類(lèi)的。

在CountDownLatch的構造器中,初始化CountDownLatch對象時(shí)會(huì )同時(shí)在其內部初始化保存一個(gè)Sync類(lèi)型的對象到sync字段用于之后的同步操作。并且傳入Sync類(lèi)構造器的count一定會(huì )大于等于0。

public CountDownLatch(int count) {      if (count < 0) throw new IllegalArgumentException("count < 0");      this.sync = new Sync(count);  }

有了Sync類(lèi)型的對象之后,我們在await()方法里就可以直接調用sync的acquireSharedInterruptibly方法來(lái)獲取同步器并陷入阻塞,等待count值變?yōu)?了。在A(yíng)QS的acquireSharedInterruptibly方法中會(huì )在調用我們重寫(xiě)的tryAcquireShared方法獲取失敗時(shí)進(jìn)入阻塞狀態(tài),直到CountDownLatch的count值變?yōu)?時(shí)才能成功獲取到同步器。

public void await() throws InterruptedException {      // 調用sync對象的獲取方法來(lái)進(jìn)入鎖等待      sync.acquireSharedInterruptibly(1);  }

而在CountDownLatch的另一個(gè)減少count值的重要方法countDown()中,我們同樣是通過(guò)調用sync上的方法來(lái)實(shí)現具體的同步功能。在這里,AQS的releaseShared(1)方法中同樣會(huì )調用我們在Sync類(lèi)中重寫(xiě)的tryReleaseShared方法來(lái)執行釋放操作,并在tryReleaseShared方法返回true時(shí)去喚醒等待隊列中的阻塞等待線(xiàn)程,讓它們在count值為0時(shí)能夠繼續執行。

public void countDown() {      sync.releaseShared(1);  }

從上文中可以看出,CoundDownLatch中的各種功能都是通過(guò)內部類(lèi)Sync來(lái)實(shí)現的,而這個(gè)Sync類(lèi)就是一個(gè)繼承自AQS的子類(lèi)。通過(guò)在內部類(lèi)Sync中重寫(xiě)了AQS的tryAcquireShared和tryReleaseShared兩個(gè)方法,我們就指定了AQS的行為策略,使其能夠符合我們對CountDownLatch功能的期望。這就是AQS的使用方法,下面我們來(lái)看一個(gè)大家可能會(huì )更熟悉的例子,來(lái)進(jìn)一步了解AQS在獨占模式下的用法。

ReentrantLock的實(shí)現

可重入鎖ReentrantLock可以說(shuō)是我們的老朋友了,從最早的synchronized關(guān)鍵字開(kāi)始,我們就開(kāi)始使用類(lèi)似的功能了??芍厝腈i的特點(diǎn)主要有兩點(diǎn):

  •  同一時(shí)間只能有一個(gè)線(xiàn)程持有

    •   如果我想保護一段代碼同一時(shí)間只能被一個(gè)線(xiàn)程所訪(fǎng)問(wèn),比如對一個(gè)隊列的插入操作。那么如果有一個(gè)線(xiàn)程已經(jīng)獲取了鎖之后在修改隊列了,那么其他也想要修改隊列的線(xiàn)程就會(huì )陷入阻塞,等待之前的這個(gè)線(xiàn)程執行完成。

  •  同一線(xiàn)程可以對一個(gè)鎖重復獲取成功多次

    •   而如果一個(gè)線(xiàn)程對同一個(gè)隊列執行了兩個(gè)插入操作,那么第二次獲取鎖時(shí)仍然會(huì )成功,而不會(huì )被***次成功獲取到的鎖所阻塞。

ReentrantLock類(lèi)的常用操作主要有三種:

  •  獲取鎖,一個(gè)線(xiàn)程一旦獲取鎖成功后就會(huì )阻塞其他線(xiàn)程獲取同一個(gè)鎖的操作,所以一旦獲取失敗,那么當前線(xiàn)程就會(huì )被阻塞

    •   最簡(jiǎn)單的獲取鎖方法就是調用public void lock()方法

  •  釋放鎖,獲取鎖之后就要在使用完之后釋放它,否則別的線(xiàn)程都將會(huì )因無(wú)法獲取鎖而被阻塞,所以我們一般會(huì )在finally中進(jìn)行鎖的釋放操作

    •   可以通過(guò)調用ReentrantLock對象的unlock方法來(lái)釋放鎖

  •  獲取條件變量,條件變量是和互斥鎖搭配使用的一種非常有用的數據結構,有興趣的讀者可以通過(guò)《從0到1實(shí)現自己的阻塞隊列(上)》這篇文章來(lái)了解條件變量具體的使用方法

    •   我們可以通過(guò)Condition newCondition()方法來(lái)獲取條件變量對象,然后調用條件變量對象上的await()、signal()、signalAll()方法來(lái)進(jìn)行使用

ReentrantLock的內部Sync類(lèi)

在ReentrantLock類(lèi)中存在兩種AQS的子類(lèi),一個(gè)實(shí)現了非公平鎖,一個(gè)實(shí)現了公平鎖。所謂的“公平”指的就是獲取互斥鎖成功返回的時(shí)間會(huì )和獲取鎖操作發(fā)起的時(shí)間順序一致,例如有線(xiàn)程A已經(jīng)持有了互斥鎖,當線(xiàn)程B、C、D按字母順序獲取鎖并進(jìn)入等待,線(xiàn)程A釋放鎖后一定是線(xiàn)程B被喚醒,線(xiàn)程B釋放鎖后一定是C先被喚醒。也就是說(shuō)鎖被釋放后對等待線(xiàn)程的喚醒順序和獲取鎖操作的順序一致。而且如果在這個(gè)過(guò)程中,有其他線(xiàn)程發(fā)起了獲取鎖操作,因為等待隊列中已經(jīng)有線(xiàn)程在等待了,那么這個(gè)線(xiàn)程一定要排到等待隊列***去,而不能直接搶占剛剛被釋放還未被剛剛被喚醒的線(xiàn)程鎖持有的鎖。

下面我們同樣先看一下ReentrantLock類(lèi)中定義的AQS子類(lèi)Sync的具體源代碼。下面是上一段說(shuō)到的非公平Sync類(lèi)和公平Sync類(lèi)兩個(gè)類(lèi)的共同父類(lèi)Sync的帶注釋源代碼,里面包含了大部分核心功能的實(shí)現。雖然下面包含了該類(lèi)完整的源代碼,但是我們現在只需要關(guān)心三個(gè)核心操作,也是我們在獨占模式下需要重寫(xiě)的三個(gè)AQS方法:tryAcquire、tryRelease和isHeldExclusively。建議在看完文章之后再回來(lái)回顧該類(lèi)中其他的方法實(shí)現,直接跳過(guò)其他的方法當然也是完全沒(méi)有問(wèn)題的。

abstract static class Sync extends AbstractQueuedSynchronizer {      private static final long serialVersionUID = -5179523762034025860L;      /**       * 實(shí)現Lock接口的lock方法,子類(lèi)化的主要原因是為了非公平版本的快速實(shí)現          */      abstract void lock();      /**       * 執行非公平的tryLock。tryAcquire方法在子類(lèi)中被實(shí)現,但是兩者都需要非公平版本的trylock方法實(shí)現。       */      final boolean nonfairTryAcquire(int acquires) {          final Thread current = Thread.currentThread();          int c = getState();          // 如果鎖還未被持有          if (c == 0) {              // 通過(guò)CAS嘗試獲取鎖              if (compareAndSetState(0, acquires)) {                  // 如果鎖獲取成功則將鎖持有者改為當前線(xiàn)程,并返回true                  setExclusiveOwnerThread(current);                  return true;              }          }          // 鎖已經(jīng)被持有,則判斷鎖的持有者是否是當前線(xiàn)程          else if (current == getExclusiveOwnerThread()) {              // 可重入鎖,如果鎖的持有者是當前線(xiàn)程,那就在state上加上新的獲取數              int nextc = c + acquires;              // 判斷新的state值有沒(méi)有溢出              if (nextc < 0) // overflow                  throw new Error("Maximum lock count exceeded");              // 將新的state更新為新的值,因為可以進(jìn)入這段代碼的只有一個(gè)線(xiàn)程              // 所以不需要線(xiàn)程安全措施              setState(nextc);              return true;          }               return false;      }      // 重寫(xiě)了AQS的獨占式釋放鎖方法      protected final boolean tryRelease(int releases) {          // 計算剩余的鎖持有量          // 因為只有當前線(xiàn)程持有該鎖的情況下才能執行這個(gè)方法,所以不需要做多線(xiàn)程保護          int c = getState() - releases;          // 如果當前線(xiàn)程未持有鎖,則直接拋出錯誤          if (Thread.currentThread() != getExclusiveOwnerThread())              throw new IllegalMonitorStateException();          boolean free = false;          // 如果鎖持有數已經(jīng)減少到0,則釋放該鎖,并清空鎖持有者          if (c == 0) {              free = true;              setExclusiveOwnerThread(null);          }          // 更新state值,只有state值被設置為0才是真正地釋放了鎖          // 所以setState和setExclusiveOwnerThread之間不需要額外的同步措施          setState(c);          return free;      }       // 當前線(xiàn)程是否持有該鎖      protected final boolean isHeldExclusively() {          return getExclusiveOwnerThread() == Thread.currentThread();      }      // 創(chuàng  )建對應的條件變量      final ConditionObject newCondition() {          return new ConditionObject();      }      // 從外層傳遞進(jìn)來(lái)的方法      // 獲取當前的鎖持有者      final Thread getOwner() {          return getState() == 0 ? null : getExclusiveOwnerThread();      }      // 獲取鎖的持有計數      // 如果當前線(xiàn)程持有了該鎖則返回state值,否則返回0      final int getHoldCount() {          return isHeldExclusively() ? getState() : 0;      }      // 判斷鎖是否已經(jīng)被持有      final boolean isLocked() {          return getState() != 0;      }  }

實(shí)際的tryAcquire方法將在公平Sync類(lèi)與非公平Sync類(lèi)兩個(gè)子類(lèi)中實(shí)現,但是這兩個(gè)子類(lèi)都需要調用父類(lèi)Sync中的非公平版本的tryAcquire&mdash;&mdash;nonfairTryAcquire方法。在這個(gè)方法中,我們主要做兩件事:

  •  當前鎖還未被人持有。在ReentrantLock中使用AQS的state來(lái)保存鎖的狀態(tài),state等于0時(shí)代表鎖沒(méi)有被任何線(xiàn)程持有,如果state大于0,那么就代表持有者對該鎖的重復獲取次數

    •   如果當前鎖還未被線(xiàn)程持有,那么就會(huì )通過(guò)compareAndSetState來(lái)原子性地修改state值,修改成功則需要設置當前線(xiàn)程為鎖的持有線(xiàn)程并返回true代表獲取成功;否則就返回

  •  鎖已被當前線(xiàn)程持有

    •   在鎖已被當前線(xiàn)程持有的情況下,就需要將state值加1代表持有者線(xiàn)程對鎖的重復獲取次數。

而對于獨占式釋放同步器的tryRelease方法,則在父類(lèi)Sync中直接實(shí)現了,兩個(gè)公平/非公平子類(lèi)調用的都是同一段代碼。首先,只有鎖的持有者才能釋放鎖,所以如果當前線(xiàn)程不是所有者線(xiàn)程在釋放操作中就會(huì )拋出異常。如果釋放操作會(huì )將持有計數清零,那么當前線(xiàn)程就不再是該鎖的持有者了,鎖會(huì )被完全釋放,而鎖的所有者會(huì )被設置為null。***,Sync會(huì )將減掉入參中的釋放數之后的新持有計數更新到AQS的state中,并返回鎖是否已經(jīng)被完全釋放了。

isHeldExclusively方法比較簡(jiǎn)單,它只是檢查鎖的持有者是否是當前線(xiàn)程。

非公平Sync類(lèi)的實(shí)現

Sync的兩個(gè)公平/非公平子類(lèi)的實(shí)現比較簡(jiǎn)單,下面是非公平版本子類(lèi)的源代碼。在非公平版本的實(shí)現中,調用lock方法首先會(huì )嘗試通過(guò)CAS修改AQS的state值來(lái)直接搶占鎖,如果搶占成功就直接將持有者設置為當前線(xiàn)程;如果搶占失敗就調用acquire方法走正常流程來(lái)獲取鎖。而在acquire方法中就會(huì )調用子類(lèi)中的tryAcquire方法并進(jìn)一步調用到上文提到的父類(lèi)中的nonfairTryAcquire方法來(lái)完成鎖獲取操作。

static final class NonfairSync extends Sync {      private static final long serialVersionUID = 7316153563782823691L;      /**       * 執行鎖操作。嘗試直接搶占,如果失敗的話(huà)就回到正常的獲取流程進(jìn)行       */      final void lock() {          // 嘗試直接搶占          if (compareAndSetState(0, 1))              // 搶占成功設置鎖所有者              setExclusiveOwnerThread(Thread.currentThread());          else              // 搶占失敗走正常獲取流程              acquire(1);      }      // 實(shí)現AQS方法,使用nonfairTryAcquire實(shí)現      protected final boolean tryAcquire(int acquires) {          return nonfairTryAcquire(acquires);      }  }

公平Sync類(lèi)的實(shí)現

而在公平版本的Sync子類(lèi)FairSync中,為了保證成功獲取到鎖的順序一定要和發(fā)起獲取鎖操作的順序一致,所以自然不能在lock方法中進(jìn)行CAS方式的搶占,只能老老實(shí)實(shí)調用acquire方法走正式流程。而acquire方法最終就會(huì )調用子類(lèi)中定義的tryAcquire來(lái)真正獲取鎖。

在tryAcquire方法中,代碼主要處理了兩種情況:

  •  當前鎖還沒(méi)有被線(xiàn)程鎖持有

    •   只有在確保等待隊列為空的情況下才能?chē)L試用CAS方式直接搶占鎖,而在等待隊列不為空的情況下,***返回了false,之后acquire方法中的代碼會(huì )將當前線(xiàn)程放入到等待隊列中阻塞等待鎖的釋放。這就保證了在獲取鎖時(shí)已經(jīng)有線(xiàn)程等待的情況下,任何線(xiàn)程都要進(jìn)入等待隊列去等待獲取鎖,而不能直接對鎖進(jìn)行獲取。

  •  當前線(xiàn)程已經(jīng)持有了該鎖

    •   如果當前線(xiàn)程已經(jīng)是該鎖的持有者了,那么就會(huì )在state值上加上本次的獲取數量來(lái)更新鎖的重復獲取次數,并返回true代表獲取鎖成功。 

static final class FairSync extends Sync {      private static final long serialVersionUID = -3000897897090466540L;      // 直接使用acquire進(jìn)行獲取鎖操作      final void lock() {          acquire(1);      }      /**       * 公平版本的tryAcquire方法。不要授予訪(fǎng)問(wèn)權限,除非是遞歸調用或者沒(méi)有等待線(xiàn)程或者這是***個(gè)調用       */      protected final boolean tryAcquire(int acquires) {          final Thread current = Thread.currentThread();          int c = getState();          // 如果鎖沒(méi)有被持有          if (c == 0) {              // 為了實(shí)現公平特性,所以只有在等待隊列為空的情況下才能直接搶占              // 否則只能進(jìn)入隊列等待              if (!hasQueuedPredecessors() &&                  compareAndSetState(0, acquires)) {                  setExclusiveOwnerThread(current);                  return true;              }          }          // 如果鎖已被持有,且當前線(xiàn)程就是持有線(xiàn)程          else if (current == getExclusiveOwnerThread()) {              // 計算新的state值              int nextc = c + acquires;              // 如果鎖計數溢出,則拋出異常              if (nextc < 0)                  throw new Error("Maximum lock count exceeded");              // 設置state狀態(tài)值              setState(nextc);              return true;          }          return false;      }  }

ReentrantLock對Sync類(lèi)對象的使用

***,我們來(lái)看看ReentrantLock類(lèi)中的lock()、unlock()、newCondition方法對Sync類(lèi)對象的使用方式。

首先是在構造器中,根據入參指定的公平/非公平模式創(chuàng )建不同的內部Sync類(lèi)對象,如果是公平模式就是用FairSync類(lèi),如果是非公平模式就是用NonfairSync類(lèi)。

public ReentrantLock(boolean fair) {      sync = fair ? new FairSync() : new NonfairSync();  }

然后在互斥鎖的鎖定方法lock()中,ReentrantLock直接使用Sync類(lèi)中的lock方法來(lái)實(shí)現了鎖的獲取功能。

public void lock() {      // 調用sync對象的lock方法實(shí)現      sync.lock();  }

在unlock()方法中也是一樣的情況,ReentrantLock直接依賴(lài)Sync類(lèi)對象來(lái)實(shí)現這個(gè)功能。

public void unlock() {      // 調用了sync對象的release方法實(shí)現      sync.release(1);  }

***一個(gè)創(chuàng )建條件變量的方法則直接依賴(lài)于A(yíng)QS中定義的方法,我們在ReentranctLock的Sync類(lèi)中并不需要做任務(wù)額外的工作,AQS就能為我們做好所有的事情。

public Condition newCondition() {      // 調用了sync對象繼承自AQS的`newCondition`方法實(shí)現      return sync.newCondition();  }

通過(guò)ReentrantLock的例子我們能夠更明顯地感受到,這些基于A(yíng)QS實(shí)現同步功能的類(lèi)中并不需要做太多額外的工作,大多數操作都是通過(guò)直接調用Sync類(lèi)對象上的方法來(lái)實(shí)現的。只要定義好了繼承自AQS的子類(lèi)Sync,并通過(guò)Sync類(lèi)重寫(xiě)幾個(gè)AQS的關(guān)鍵方法來(lái)指定AQS的行為策略,就可以實(shí)現風(fēng)格迥異的各種同步工具類(lèi)了。

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。

亚洲精品乱码久久久久66| 国产精品一区二区香蕉| 后入内射国产一区二区| 色欧美片视频在线观看| 看女被强伦轩视频| 我想把我的乌龟蹭你的扇贝视频|