java.util.concurrent.Locks使用指南
1.概述
簡而言之,鎖是一種比標準同步塊更靈活,更復雜的線程同步機制。
自Java 1.5以來,Lock接口一直存在。它在java.util.concurrent.lock包中定義,它提供了大量的鎖定操作。
在本文中,我們將探討Lock接口及其應用程序的不同實現。
2.?鎖定(Lock)和同步塊(Synchronized?)之間的差異
- 同步塊被完全包含在方法中(創建和釋放鎖在同一個方法內);? ? ? ?Lock可以將lock()?和?unlock()放在不同的方法中
- synchronized塊不支持公平性,一旦鎖釋放,任何線程可能獲得鎖;? ? ? ?通過指定公平屬性,我們可以在Lock?API中實現公平。它確保最長的等待線程可以訪問鎖
- 如果線程無法訪問同步塊,則會阻塞該線程;? ? ? ? ? ?Lock?API提供的tryLock()方法,只有當鎖可用且沒有任何其他線程持有時,線程才會獲取鎖定。這減少了線程等待鎖定的阻塞時間(可以設置嘗試獲取鎖的時間)
- 處于“等待”狀態以獲取對同步塊的訪問的線程不能被中斷;? ? ? ? Lock??API提供了一種方法lockInterruptibly()??,其可以用來中斷等待鎖線程。
3. Lock?API
我們來看看Lock接口中的方法:
- void lock()??-獲取鎖(如果可用);?如果鎖不可用,則線程會被阻塞,直到鎖被釋放
- void lockInterruptibly()?- 這類似于?lock(),但它允許被阻塞的線程被中斷并通過拋出的java.lang.InterruptedException恢復執行
- boolean tryLock()?- 這是?lock()方法的非阻塞版本;?它會立即嘗試獲取鎖定,如果鎖定成功則返回true
- boolean tryLock(long timeout,TimeUnit timeUnit)?-這類似于?tryLock(),除了它在放棄嘗試獲取?Lock之前等待給定的超時
- void?unlock()?- 解鎖Lock實例
執行完畢應始終釋放鎖以避免死鎖情況。使用鎖的推薦代碼塊應包含try / catch和finally塊:
Lock lock = ...; lock.lock(); try {// access to the shared resource } finally {lock.unlock(); }除了??Lock接口之外,我們還有一個ReadWriteLock接口,它維護一對鎖,一個用于只讀操作,另一個用于寫操作。只要沒有寫入,讀鎖可以由多個線程同時保持。
ReadWriteLock聲明獲取讀或寫鎖的方法:
- Lock readLock()?-返回用于讀取的鎖
- Lock writeLock()?- 返回用于寫入的鎖
4.?鎖的實現
4.1.ReentrantLock(重入鎖)
ReentrantLock類實現Lock接口。它提供了相同的并發和內存語義.
public class SharedObject {//...ReentrantLock lock = new ReentrantLock();int counter = 0;public void perform() {lock.lock();try {// Critical section herecount++;} finally {lock.unlock();}}//... }我們需要確保在try-finally塊中包裝lock()和unlock()調用以避免死鎖情況。
讓我們看看tryLock()如何使用:
public void performTryLock(){//...boolean isLockAcquired = lock.tryLock(1, TimeUnit.SECONDS);if(isLockAcquired) {try {//Critical section here} finally {lock.unlock();}}//... }在這種情況下,調用tryLock()的線程將最多等待一秒鐘(如果直接拿到鎖則不用等待),并且如果鎖不可用則放棄等待。
4.2.ReentrantReadWriteLock
ReentrantReadWriteLock類實現ReadWriteLock接口。
讓我們看一下線程獲取ReadLock或WriteLock的規則:
- 讀鎖?- 如果沒有線程獲得寫鎖或請求它,則多個線程可以獲取讀鎖
- 寫鎖-? 如果沒有線程正在讀取或寫入,則只有一個線程可以獲取寫入鎖
讓我們看看如何使用ReadWriteLock:
public class SynchronizedHashMapWithReadWriteLock {Map<String,String> syncHashMap = new HashMap<>();ReadWriteLock lock = new ReentrantReadWriteLock();// ...Lock writeLock = lock.writeLock();public void put(String key, String value) {try {writeLock.lock();syncHashMap.put(key, value);} finally {writeLock.unlock();}}...public String remove(String key){try {writeLock.lock();return syncHashMap.remove(key);} finally {writeLock.unlock();}}//... }?
Lock readLock = lock.readLock(); //... public String get(String key){try {readLock.lock();return syncHashMap.get(key);} finally {readLock.unlock();} }public boolean containsKey(String key) {try {readLock.lock();return syncHashMap.containsKey(key);} finally {readLock.unlock();} }4.3.StampedLock
StampedLock在Java 8中引入。它還支持讀寫鎖定。但是,鎖獲取方法會返回一個用于釋放鎖或檢查鎖是否仍然有效的戳記:
public class StampedLockDemo {Map<String,String> map = new HashMap<>();private StampedLock lock = new StampedLock();public void put(String key, String value){long stamp = lock.writeLock();try {map.put(key, value);} finally {lock.unlockWrite(stamp);}}public String get(String key) throws InterruptedException {long stamp = lock.readLock();try {return map.get(key);} finally {lock.unlockRead(stamp);}} }StampedLock提供的另一個功能是樂觀鎖定。大多數時候,讀操作不需要等待寫操作完成,因此不需要真正的讀鎖。
如果出現并發,我們可以升級到讀鎖:
public String readWithOptimisticLock(String key) {long stamp = lock.tryOptimisticRead();String value = map.get(key);if(!lock.validate(stamp)) {stamp = lock.readLock();try {return map.get(key);} finally {lock.unlock(stamp); }}return value; }5.使用條件
該條件類提供了一個線程等待在執行關鍵部分出現一些狀況的能力。
當線程獲得對臨界區的訪問但沒有執行其操作的必要條件時,可能會發生這種情況。例如,讀者線程可以訪問共享隊列的鎖,該隊列仍然沒有任何數據要消耗。
傳統上,Java?為線程互通提供了wait(),notify()和notifyAll()方法。條件有類似的機制,但另外,我們可以指定多個條件:
public class ReentrantLockWithCondition {Stack<String> stack = new Stack<>();int CAPACITY = 5;ReentrantLock lock = new ReentrantLock();Condition stackEmptyCondition = lock.newCondition();Condition stackFullCondition = lock.newCondition();public void pushToStack(String item){try {lock.lock();while(stack.size() == CAPACITY) {stackFullCondition.await();}stack.push(item);stackEmptyCondition.signalAll();} finally {lock.unlock();}}public String popFromStack() {try {lock.lock();while(stack.size() == 0) {stackEmptyCondition.await();}return stack.pop();} finally {stackFullCondition.signalAll();lock.unlock();}} }對比:
Condition提供的方法和Java原生的wait(),notify(),notifyAll()功能類似,但是可以同時創建多個Condition條件,而java原生則不能指定特定的條件。
六,結論
在本文中,我們已經看到了Lock接口和新引入的StampedLock類的不同實現。我們還探討了如何使用Condition類來處理多個條件。
轉載于:https://www.cnblogs.com/gc65/p/10631176.html
總結
以上是生活随笔為你收集整理的java.util.concurrent.Locks使用指南的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: websocket传输canvas图像数
- 下一篇: jQuey基础思维导图梳理1