首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 多線程同步問題探究(三、上):認識 ReentrantLock 重入鎖

     編輯:Java 相關知識

synchronized 的限制

  1. 無法中斷正在等待獲得鎖的線程,也無法透過投票獲得鎖
  2. 鎖獲取/釋放在相同堆棧幀,大多數情況無問題,但確有更適合非塊結構鎖定的情況

java.util.concurrent.locks.Lock 框架是鎖定的抽象,允許用 Java 類實現鎖定而非語言特性,為多種實現留下空間(不同調度算法、性能特性、鎖定語義)。

ReentrantLock 介紹

可重入互斥鎖,與 synchronized 隱式監視器鎖有相同基本行為和語義,但功能更強大。擁有獲取計數器:擁有鎖的線程再次獲得鎖則計數器+1,需釋放兩次才真正釋放。模仿 synchronized 語義:線程進入已擁有監視器保護的同步塊允許繼續,退出第二個同步塊不釋放鎖,退出第一個才釋放。

實現 Lock 介面,擁有相同並發性和記憶體語義,新增鎖投票、定時鎖等待、可中斷鎖等待特性。激烈爭用下提供更佳性能(JVM 芃更少時間調度線程,更多時間執行線程)。

程式碼對比:synchronized vs ReentrantLock

使用 synchronized(兩段同步塊用同一物件鎖)

每線程執行 10 秒,徹底完成兩同步塊動作才釋放鎖,3 線程共 30 秒。

使用 synchronized(兩段同步塊用不同物件鎖)

線程釋放第一鎖後第二線程可進入第一塊,第一線程繼續執行第二塊。有 10 秒雙線程並行,總時間 21 秒(節省 1/3)。優化公式:(n+1)/2n,n 為線程數;m 個同步塊時:((m-1)n+1)/mn。理想情況下 m,n→∞ 效率提升近 100%。

使用 ReentrantLock

ReentrantLock lock1 = new ReentrantLock(false);
ReentrantLock lock2 = new ReentrantLock(false);
// ...
lock1.lock();
try {
  // 關鍵區域 1
} finally {
  lock1.unlock();
}
lock2.lock();
try {
  // 關鍵區域 2
} finally {
  lock2.unlock();
}

結果與不同物件鎖的 synchronized 相同。優點:

  1. 鎖獲取/釋放時機由程式碼控制,可定制性更好
  2. 免去為同步塊尋找合適物件鎖的考量
  3. 最佳實踐:try/finally 結合,lock() 在 try 前,unlock() 在 finally 中

建構子參數 false 的含義?

傳遞 false 表示非公平鎖。傳遞 true 則為公平鎖,詳見下節「Fair or Unfair? It is a question...」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved