Lock是一個接口,提供了無條件的、可輪詢的、定時的、可中斷的鎖獲取操做,全部加鎖和解鎖的方法都是顯式的。包路徑是:java.util.concurrent.locks.Lock
。核心方法有 lock()
,unlock()
,tryLock()
,實現類有 ReentrantLock
、ReentrantReadWriteLock.ReadLock
、ReentrantReadWriteLock.WriteLock
。java
** 方法及說明 **多線程
public abstract interface Lock { // 獲取鎖。若是鎖不可用,出於線程調度目的,將禁用當前線程,而且在得到鎖以前, // 該線程將一直處於休眠狀態 void lock(); // 若是當前線程未被中斷,則獲取鎖。若是鎖可用,則獲取鎖,並當即返回。 // 若是鎖不可用,出於線程調度目的,將禁用當前線程,而且在發生如下兩種狀況之一之前,該線程將一直處於休眠狀態: // 鎖由當前線程得到;或者其餘某個線程中斷當前線程,而且支持對鎖獲取的中斷。 // 若是當前線程:在進入此方法時已經設置了該線程的中斷狀態; // 或者在獲取鎖時被中斷,而且支持對鎖獲取的中斷,則將拋出`InterruptedException`,並清除當前線程的已中斷狀態 void lockInterruptibly() throws InterruptedException; // 僅在調用時鎖爲空閒狀態才獲取該鎖。若是鎖可用,則獲取鎖,並當即返回值 true。 // 若是鎖不可用,則此方法將當即返回值 false。一般對於那些不是必須獲取鎖的操做可能有用 boolean tryLock(); // 若是鎖在給定的等待時間內空閒,而且當前線程未被中斷,則獲取鎖。 // 若是鎖可用,則此方法將當即返回值 true。若是鎖不可用,出於線程調度目的, // 將禁用當前線程,而且在發生如下三種狀況之一前,該線程將一直處於休眠狀態 boolean tryLock(long time, TimeUnit unit) throws InterruptedException; // 釋放鎖。對應於 lock()、tryLock()、tryLock(time, unit)、lockInterruptibly() 等操做, // 若是成功的話應該對應着一個`unlock()`,這樣能夠避免死鎖或者資源浪費 void unlock(); // 返回用來與此 Lock 實例一塊兒使用的 Condition 實例 Condition newCondition(); }
ReentrantLock是Lock的實現類,是一個互斥的同步器,它具備擴展的能力。在競爭條件下,ReentrantLock 的實現要比如今的 synchronized 實現更具備可伸縮性。(有可能在 JVM 的未來版本中改進 synchronized 的競爭性能)這意味着當許多線程都競爭相同鎖定時,使用 ReentrantLock 的吞吐量一般要比 synchronized 好。換句話說,當許多線程試圖訪問 ReentrantLock 保護的共享資源時,JVM 將花費較少的時間來調度線程,而用更多個時間執行線程。雖然 ReentrantLock 類有許多優勢,可是與同步相比,它有一個主要缺點 — 它可能忘記釋放鎖定。ReentrantLock是在工做中對方法塊加鎖使用頻率最高的。性能
** 使用方法以下: **線程
class X { private final ReentrantLock lock = new ReentrantLock(); // … public void m() { lock.lock(); // 得到鎖 try { // … 方法體 } finally { lock.unlock();//解鎖 } } }
** Lock與synchronized 的比較: **code
請注意如下兩種方式的區別:對象
public class ReentrantLockDemo { public static void main(String[] args) { final Count ct = new Count(); for (int i = 0; i < 2; i++) { new Thread() { public void run() { ct.get(); } }.start(); } for (int i = 0; i < 2; i++) { new Thread() { public void run() { ct.put(); } }.start(); } } } class Count { public void get() { final ReentrantLock lock = new ReentrantLock(); try { lock.lock(); // 加鎖 System.out.println(Thread.currentThread().getName() + " get begin"); Thread.sleep(1000);// 模仿幹活 System.out.println(Thread.currentThread().getName() + " get end"); lock.unlock(); // 解鎖 } catch (InterruptedException e) { e.printStackTrace(); } } public void put() { final ReentrantLock lock = new ReentrantLock(); try { lock.lock(); // 加鎖 System.out.println(Thread.currentThread().getName() + " put begin"); Thread.sleep(1000);// 模仿幹活 System.out.println(Thread.currentThread().getName() + " put end"); lock.unlock(); // 解鎖 } catch (InterruptedException e) { e.printStackTrace(); } } }
運行結果以下(每次運行結果都是不同的,仔細體會一下):接口
Thread-0 get begin Thread-1 get begin Thread-2 put begin Thread-3 put begin Thread-0 get end Thread-2 put end Thread-3 put end Thread-1 get end
ReentrantLockDemo 類的內容不變,將Count中的ReentrantLock改爲全局變量,以下所示:資源
class Count { final ReentrantLock lock = new ReentrantLock(); public void get() { try { lock.lock(); // 加鎖 System.out.println(Thread.currentThread().getName() + " get begin"); Thread.sleep(1000);// 模仿幹活 System.out.println(Thread.currentThread().getName() + " get end"); lock.unlock(); // 解鎖 } catch (InterruptedException e) { e.printStackTrace(); } } public void put() { try { lock.lock(); // 加鎖 System.out.println(Thread.currentThread().getName() + " put begin"); Thread.sleep(1000);// 模仿幹活 System.out.println(Thread.currentThread().getName() + " put end"); lock.unlock(); // 解鎖 } catch (InterruptedException e) { e.printStackTrace(); } } }
運行結果以下(每次運行結果同樣的,仔細體會一下):get
Thread-0 get begin Thread-0 get end Thread-1 get begin Thread-1 get end Thread-2 put begin Thread-2 put end Thread-3 put begin Thread-3 put end