ReentrantLock和讀寫鎖
阿新 • • 發佈:2018-05-27
輪詢 兩個 對象 ret 異常 sed 5.0 之前 有效
lockInterruptibly方法能夠在獲取鎖的同時保持對中斷的響應,因此無需創建其它類型的不可中斷阻塞操作。
在Java5.0之前,只有synchronized(內置鎖)和volatile. Java5.0後引入了顯示鎖ReentrantLock.
ReentrantLock概況
ReentrantLock是可重入的鎖,它不同於內置鎖, 它在每次使用都需要顯示的加鎖和解鎖, 而且提供了更高級的特性:公平鎖, 定時鎖, 有條件鎖, 可輪詢鎖, 可中斷鎖. 可以有效避免死鎖的活躍性問題.ReentrantLock實現了
Lock接口:
public interface Lock { //阻塞直到獲得鎖或者中斷 void lock(); //阻塞直到獲得鎖或者中斷拋異常 void lockInterruptibly() throws InterruptedException; //只有鎖可用時才獲得,否則直接返回 boolean tryLock(); //只有鎖在指定時間內可用時才獲得,否則直接返回,中斷時拋異常 boolean tryLock(long time, TimeUnit unit) throws InterruptedException; void unlock(); //返回一個綁定在這個鎖上的條件 Condition newCondition(); }
Lock使用
Lock lock = new ReentrantLock(); lock.lock(); try{ //更新對象狀態 }finally{ //這裏註意,一定要有finally代碼塊去解鎖 //否則容易造成死鎖等活躍性問題 lock.unlock(); }
ReentrantLock特性
輪詢鎖的和定時鎖
可輪詢和可定時的鎖請求是通過tryLock()方法實現的,和無條件獲取鎖不一樣. ReentrantLock可以有靈活的容錯機制.死鎖的很多情況是由於順序鎖引起的, 不同線程在試圖獲得鎖的時候阻塞,並且不釋放自己已經持有的鎖, 最後造成死鎖. tryLock()方法在試圖獲得鎖的時候,如果該鎖已經被其它線程持有,則按照設置方式立刻返回,而不是一直阻塞等下去,同時在返回後釋放自己持有的鎖.可以根據返回的結果進行重試或者取消,進而避免死鎖的發生.
公平性
ReentrantLock構造函數中提供公平性鎖和非公平鎖(默認)兩種選擇。所謂公平鎖,線程將按照他們發出請求的順序來獲取鎖,不允許插隊;但在非公平鎖上,則允許插隊:當一個線程發生獲取鎖的請求的時刻,如果這個鎖是可用的,那這個線程將跳過所在隊列裏等待線程並獲得鎖。我們一般希望所有鎖是非公平的。因為當執行加鎖操作時,公平性將講由於線程掛起和恢復線程時開銷而極大的降低性能。考慮這麽一種情況:A線程持有鎖,B線程請求這個鎖,因此B線程被掛起;A線程釋放這個鎖時,B線程將被喚醒,因此再次嘗試獲取鎖;與此同時,C線程也請求獲取這個鎖,那麽C線程很可能在B線程被完全喚醒之前獲得、使用以及釋放這個鎖。這是種雙贏的局面,B獲取鎖的時刻(B被喚醒後才能獲取鎖)並沒有推遲,C更早地獲取了鎖,並且吞吐量也獲得了提高。在大多數情況下,非公平鎖的性能要高於公平鎖的性能。可中斷獲鎖獲取操作
讀寫鎖ReadWriteLock
?ReentrantLock是一種標準的互斥鎖,每次最多只有一個線程能持有鎖。讀寫鎖不一樣,暴露了兩個Lock對象,其中一個用於讀操作,而另外一個用於寫操作。
-
public interface ReadWriteLock { /** * Returns the lock used for reading. * * @return the lock used for reading. */ Lock readLock(); /** * Returns the lock used for writing. * * @return the lock used for writing. */ Lock writeLock(); }
- 釋放優先
- 讀線程插隊
- 重入性
- 降級
- 升級
public class ReadWriteMap<K, V> { private Map<K, V> map; private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final Lock readLock = lock.readLock(); private final Lock writeLock = lock.writeLock(); public ReadWriteMap(Map<K, V> map) { this.map = map; } public V get(K key) { readLock.lock(); try { return map.get(key); } finally { readLock.unlock(); } } public void put(K key, V value) { writeLock.lock(); try { map.put(key, value); } finally { writeLock.unlock(); } } }
ReentrantLock和讀寫鎖