java併發編程(十二): 顯示鎖

顯示鎖:

Lock與ReentrantLock:

  • Lock接口
void lock(); //獲取鎖
void lockInterruptibly() throws InterruptedException; //獲取鎖,且當前線程可被中斷
boolean tryLock(); //嘗試獲取鎖,true獲取到鎖, false未獲取到鎖
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock(); //釋放鎖
Condition newCondition(); //在當前鎖上建立一個等待條件
  • Lock的標準用法
Lock lock = new ReentrantLock();
		
lock.lock();
try{
	// to do sth.
} finally{
	lock.unlock(); //需要在finally中釋放鎖
}

輪詢鎖與定時鎖:

  • 輪詢鎖定時鎖可由tryLock來實現。
  • 輪詢鎖,定時鎖能夠避免死鎖的發生。
  • 由tryLock實現輪詢鎖
public boolean transferMoney(Account fromAcct,
				 Account toAcct,
			        int amount,
				 long timeout,
				 TimeUnit unit){
	long fixedDelay = getFixedDelayComponentNanos(timeout, unit);
	long randMod = getRandomDelayModulusNanos(timeout, unit);
	long stopTime = System.nanoTime() + unit.toNanos(timeout);
		
	while (true){
		if (fromAcct.lock.tryLock()){ //若獲取到源帳戶鎖
			try{
				if (toAcct.lock.tryLock()){ //若獲取到目的帳戶鎖
					try{
						if (fromAcct.getBalance() < amount){
							throw new RuntimeException("money.not.enough");
						} else{
							fromAcct.debit(amount);
							toAcct.credit(amount);
							return true;
						}
					} finally{
						toAcct.lock.unlock();
					}
				}
			} finally{
				fromAcct.lock.unlock();
			}
		}
		if (System.nanoTime() < stopTime){
			return false;
		}
		try {
			Thread.sleep(fixedDelay + rand.nextLong()%randMod);
		} catch (InterruptedException e) {
				
		}
	}
}
你也能夠採用定時實現:
lock.tryLock(timeout, unit);

可中斷的鎖獲取操做:

lock.lockInterruptibly();
try{
	// maybe throws InterruptedException
	doSomething();
} finally{
	lock.unlock();
}

非塊結構的加鎖:

  • ConcurrentHashMap中的分段鎖實現。

性能考慮因素:

  • 上圖是對HashMap的測試,可見在jdk1.5時ReentrantLock比內置鎖吞吐量高,jdk1.6差別就很小了。
  • 性能是一個不斷變化的指標,若是在昨天的測試中發現X比Y更快,那麼在今天就可能已通過時了。

公平性:

  • ReentrantLock可初始化爲公平非公平的鎖。
  • 大多數狀況下非公平鎖的性能高於公平鎖的性能
  • 基於公平鎖非公平鎖ConcurrentHashMap對HashMap進行吞吐量測試。

  • 持有鎖的時間相對較長,或者請求鎖的平均時間間隔較長,那麼應該使用公平鎖

在Synchronized和ReentrantLock之間做出選擇:

  • 在一些內置鎖沒法知足需求的狀況下,ReentrantLock能夠做爲一種高級工具。當須要一些高級功能時才應該使用ReentrantLock,這些功能包括:可定時可輪詢可中斷公平隊列,及非塊結構的鎖。不然仍是應該優先使用synchronized.

讀--寫鎖:

//讀寫鎖容許同時多個線程讀, 或最多一個線程寫
public interface ReadWriteLock {
    Lock readLock();
    Lock writeLock();
}
  • 讀寫鎖的可選實現:

       1. 釋放優先。當寫入鎖釋放後,應該優先選擇讀線程寫線程,仍是最早發出請求的線程? java

       2. 讀線程插隊。鎖由讀線程持有,寫線程再等待,再來一個讀線程,是繼續讓讀線程訪問,仍是讓寫線程訪問. 併發

       3. 重入性。讀取鎖和寫入鎖是否可重入? dom

       4. 降級。將寫入鎖降級爲讀取鎖。 高併發

       5. 升級。將讀取鎖升級爲寫入鎖。 工具

  • 當鎖的持有時間較長而且大部分操做都不會修改被守護的資源時,可用讀寫鎖提升併發性。
/**
 * 讀寫鎖來包裝Map
 */
public class ReadWriteMap<K, V> {
	private final Map<K, V> map;
	private final ReadWriteLock lock = new ReentrantReadWriteLock();
	private final Lock r = lock.readLock();
	private final Lock w = lock.writeLock();
	
	public ReadWriteMap(Map<K, V> map){
		this.map = map;
	}
	
	// 其餘寫操做...
	
	public V put(K key, V value){
		w.lock(); //請求寫鎖
		try{
			return map.put(key, value);
		} finally{
			w.unlock(); //勿忘
		}
	}
	
	// 其餘讀操做...
	
	public V get(K key){
		r.lock(); //請求讀鎖
		try{
			return map.get(key);
		} finally{
			r.unlock(); //勿忘
		}
	}
}
  • 對ArrayList使用ReentrantLock和ReadWriteLock測試吞吐量。

不吝指正。 性能

相關文章
相關標籤/搜索