Java併發編程 - 顯示鎖Lock和ReentrantLock

Lock

Lock是一個接口,提供了無條件的、可輪詢的、定時的、可中斷的鎖獲取操做,全部加鎖和解鎖的方法都是顯式的。包路徑是:java.util.concurrent.locks.Lock。核心方法有 lock()unlock()tryLock(),實現類有 ReentrantLockReentrantReadWriteLock.ReadLockReentrantReadWriteLock.WriteLockjava

** 方法及說明 **多線程

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

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

  1. Lock使用起來比較靈活,可是必須有釋放鎖的動做;
  2. Lock必須手動釋放和開啓鎖,synchronized 不須要;
  3. Lock只適用與代碼塊鎖,而synchronized 對象之間的互斥關係;

示例

請注意如下兩種方式的區別:對象

第一種方式:兩個方法之間的鎖是獨立的

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
相關文章
相關標籤/搜索