1. 程式人生 > >java多執行緒--“鎖”總覽

java多執行緒--“鎖”總覽

根據鎖的新增到Java中的時間,Java中的鎖,可以分為"同步鎖"和"JUC包中的鎖"。

同步鎖

  即通過synchronized關鍵字來進行同步,實現對競爭資源的互斥訪問的鎖。Java 1.0版本中就已經支援同步鎖了。

  同步鎖的原理是,對於每一個物件,有且僅有一個同步鎖;不同的執行緒能共同訪問該同步鎖。但是,在同一個時間點,該同步鎖能且只能被一個執行緒獲取到。這樣,獲取到同步鎖的執行緒就能進行CPU排程,從而在CPU上執行;而沒有獲取到同步鎖的執行緒,必須進行等待,直到獲取到同步鎖之後才能繼續執行。這就是,多執行緒通過同步鎖進行同步的原理!

  關於"同步鎖"的更多內容,請參考前面的內容。

JUC包中的鎖 

相比同步鎖,JUC包中的鎖的功能更加強大,它為鎖提供了一個框架,該框架允許更靈活地使用鎖,只是它的用法更難罷了。

  JUC包中的鎖,包括:Lock介面,ReadWriteLock介面,LockSupport阻塞原語,Condition條件,AbstractOwnableSynchronizer/AbstractQueuedSynchronizer/AbstractQueuedLongSynchronizer三個抽象類,ReentrantLock獨佔鎖,ReentrantReadWriteLock讀寫鎖。由於CountDownLatch,CyclicBarrier和Semaphore也是通過AQS來實現的;因此,我也將它們歸納到鎖的框架中進行介紹。

  先看看鎖的框架圖,如下所示。

01. Lock介面

  JUC包中的 Lock 介面支援那些語義不同(重入、公平等)的鎖規則。所謂語義不同,是指鎖可是有"公平機制的鎖"、"非公平機制的鎖"、"可重入的鎖"等等。"公平機制"是指"不同執行緒獲取鎖的機制是公平的",而"非公平機制"則是指"不同執行緒獲取鎖的機制是非公平的","可重入的鎖"是指同一個鎖能夠被一個執行緒多次獲取。

02. ReadWriteLock

  ReadWriteLock 介面以和Lock類似的方式定義了一些讀取者可以共享而寫入者獨佔的鎖。JUC包只有一個類實現了該介面,即 ReentrantReadWriteLock,因為它適用於大部分的標準用法上下文。但程式設計師可以建立自己的、適用於非標準要求的實現。

03. AbstractOwnableSynchronizer/AbstractQueuedSynchronizer/AbstractQueuedLongSynchronizer
  AbstractQueuedSynchronizer就是被稱之為AQS的類,它是一個非常有用的超類,可用來定義鎖以及依賴於排隊阻塞執行緒的其他同步器;ReentrantLock,ReentrantReadWriteLock,CountDownLatch,CyclicBarrier和Semaphore等這些類都是基於AQS類實現的。AbstractQueuedLongSynchronizer 類提供相同的功能但擴充套件了對同步狀態的 64 位的支援。兩者都擴充套件了類 AbstractOwnableSynchronizer(一個幫助記錄當前保持獨佔同步的執行緒的簡單類)。


04. LockSupport
  LockSupport提供“建立鎖”和“其他同步類的基本執行緒阻塞原語”。
  LockSupport的功能和"Thread中的Thread.suspend()和Thread.resume()有點類似",LockSupport中的park() 和 unpark() 的作用分別是阻塞執行緒和解除阻塞執行緒。但是park()和unpark()不會遇到“Thread.suspend 和 Thread.resume所可能引發的死鎖”問題。

05. Condition
  Condition需要和Lock聯合使用,它的作用是代替Object監視器方法,可以通過await(),signal()來休眠/喚醒執行緒。
Condition 介面描述了可能會與鎖有關聯的條件變數。這些變數在用法上與使用 Object.wait 訪問的隱式監視器類似,但提供了更強大的功能。需要特別指出的是,單個 Lock 可能與多個 Condition 物件關聯。為了避免相容性問題,Condition 方法的名稱與對應的 Object 版本中的不同。

  06. ReentrantLock
  ReentrantLock是獨佔鎖。所謂獨佔鎖,是指只能被獨自佔領,即同一個時間點只能被一個執行緒鎖獲取到的鎖。ReentrantLock鎖包括"公平的ReentrantLock"和"非公平的ReentrantLock"。"公平的ReentrantLock"是指"不同執行緒獲取鎖的機制是公平的",而"非公平的  ReentrantLock"則是指"不同執行緒獲取鎖的機制是非公平的",ReentrantLock是"可重入的鎖"。
  ReentrantLock的UML類圖如下:

  (01) ReentrantLock實現了Lock介面。
  (02) ReentrantLock中有一個成員變數sync,sync是Sync型別;Sync是一個抽象類,而且它繼承於AQS。
  (03) ReentrantLock中有"公平鎖類"FairSync和"非公平鎖類"NonfairSync,它們都是Sync的子類。ReentrantReadWriteLock中sync物件,是FairSync與NonfairSync中的一種,這也意味著ReentrantLock是"公平鎖"或"非公平鎖"中的一種,ReentrantLock預設是非公平鎖。

07. ReentrantReadWriteLock
  ReentrantReadWriteLock是讀寫鎖介面ReadWriteLock的實現類,它包括子類ReadLock和WriteLock。ReentrantLock是共享鎖,而WriteLock是獨佔鎖。
  ReentrantReadWriteLock的UML類圖如下:


  (01) ReentrantReadWriteLock實現了ReadWriteLock介面。
  (02) ReentrantReadWriteLock中包含sync物件,讀鎖readerLock和寫鎖writerLock。讀鎖ReadLock和寫鎖WriteLock都實現了Lock介面。
  (03) 和"ReentrantLock"一樣,sync是Sync型別;而且,Sync也是一個繼承於AQS的抽象類。Sync也包括"公平鎖"FairSync和"非公平鎖"NonfairSync。


08. CountDownLatch
  CountDownLatch是一個同步輔助類,在完成一組正在其他執行緒中執行的操作之前,它允許一個或多個執行緒一直等待。
  CountDownLatch的UML類圖如下:


  CountDownLatch包含了sync物件,sync是Sync型別。CountDownLatch的Sync是例項類,它繼承於AQS。

09. CyclicBarrier
  CyclicBarrier是一個同步輔助類,允許一組執行緒互相等待,直到到達某個公共屏障點 (common barrier point)。因為該 barrier 在釋放等待執行緒後可以重用,所以稱它為迴圈 的 barrier。
  CyclicBarrier的UML類圖如下:


  CyclicBarrier是包含了"ReentrantLock物件lock"和"Condition物件trip",它是通過獨佔鎖實現的。
  CyclicBarrier和CountDownLatch的區別是:
  (01) CountDownLatch的作用是允許1或N個執行緒等待其他執行緒完成執行;而CyclicBarrier則是允許N個執行緒相互等待。
  (02) CountDownLatch的計數器無法被重置;CyclicBarrier的計數器可以被重置後使用,因此它被稱為是迴圈的barrier。

10. Semaphore
  Semaphore是一個計數訊號量,它的本質是一個"共享鎖"。
  訊號量維護了一個訊號量許可集。執行緒可以通過呼叫acquire()來獲取訊號量的許可;當訊號量中有可用的許可時,執行緒能獲取該許可;否則執行緒必須等待,直到有可用的許可為止。 執行緒可以通過release()來釋放它所持有的訊號量許可。
  Semaphore的UML類圖如下:


  和"ReentrantLock"一樣,Semaphore包含了sync物件,sync是Sync型別;而且,Sync也是一個繼承於AQS的抽象類。Sync也包括"公平訊號量"FairSync和"非公平訊號量"NonfairSync。