【Java學習筆記(八十三)】之 ReentrantLock類,Condition類,ReentrantReadWriteLock類
技術標籤:# 多執行緒Java學習筆記多執行緒併發程式設計java
本文章由公號【開發小鴿】釋出!歡迎關注!!!
老規矩–妹妹鎮樓:
一. Lock的使用
(一) ReentrantLock類
之前我們使用了synchronized關鍵字實現執行緒之間的同步互斥,在JDK1.5中添加了ReentrantLock類也能夠達到同樣的效果,並且擴充套件了新的功能。
1. lock() 與 unlock()
建立一個新的ReentrantLock鎖物件,呼叫該鎖物件的lock()方法獲得鎖,執行緒呼叫了該方法,就持有了物件監視器,其他執行緒只有等待鎖被釋放時再次爭搶。同樣的,呼叫該所物件的unlock()方法釋放鎖。
private Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();
(二) Condition類
我們可以通過Condition物件實現等待/通知模式,這是在JDK5中出現的技術,有較好的靈活性,可以實現多路通知,即在一個Lock物件內建立多個Condition(物件監視器)例項,執行緒物件可以註冊在指定的Condition中,從而可以有選擇性地進行執行緒通知。而synchronized相當於整個Lock物件中只有一個單一的Condition物件,所有執行緒都註冊在一個物件上,通知是隨機的。
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
contion.await();
condition,signal();
首先在一個執行緒中呼叫Lock物件的lock()方法獲取鎖物件,然後呼叫Condition物件的await()方法,使當前執行任務的執行緒進入等待狀態,最後呼叫Condition物件的signal()方法,通知該Condition物件處理等待中的執行緒。還有signalAll()方法是喚醒所有等待的執行緒。
將不同的執行緒註冊到不同的Condition物件中,通過呼叫不同的Condition物件的notifyAll()方法或者notify()方法就可以控制喚醒的執行緒物件。
(三) 生產者/消費者模式
與之前使用wait()/notify()一樣,這裡使用的是Condition物件的await()/signal(), signalAll()方法。
(四) 公平鎖與非公平鎖
鎖物件Lock分為公平鎖和非公平鎖。公平鎖表示執行緒獲取鎖的順序是按照執行緒加鎖的順序來分配的,即先來先得的FIFO順序,但是隻能保證大多數是按照順序的,總會有少數不按順序分配的。而非公平鎖就是隨機獲取鎖的機制。
在建立ReentrantLock鎖物件的時候,傳入一個Boolean值表示是否是公平鎖:
Lock lock = new ReentrantLock(true);
(五) Lock鎖物件的方法
1. getHoldCount()
該方法查詢當前執行緒保持此鎖物件的個數,也就是該鎖物件呼叫lock()方法的次數。
lock.getHoldCount();
2. getQueueLength()
返回正在等待獲取此鎖物件的執行緒估計數,如共有5個執行緒,當1個執行緒先執行了await()方法後,那麼還有4個執行緒在等待著該鎖物件的釋放。
lock.getQueueLength();
3. getWaitQueueLength(Condition condition)
返回等待與此鎖物件相關的給定條件Condition的執行緒估計數,如有5個執行緒,每個執行緒都繫結在同一個Condition物件上,並且呼叫了該Condition物件的await()方法,則呼叫getWaitQueueLength(Condition condition)方法返回的是5。關鍵點是那個Conditino物件繫結的執行緒數量。
lock.getWaitQueueLength(newCondition);
4. hasQueuedThread()
查詢是否有執行緒正在等待獲取此鎖物件。
lock.hasQueuedThread();
5. hasQueuedThread(Thread thread)
查詢指定的執行緒是否正在等待獲取此鎖物件。
lock.hasQueuedThread(thread);
6. hasWaiters(Condition condition)
查詢是否有執行緒正在等待與此鎖物件有關的Condition條件
lock.hasWaiters(condition);
7. isFair()
判斷當前的鎖物件是不是公平鎖,預設的情況下,ReentrantLock類使用的是非公平鎖。
lock.isFair();
8. isHeldByCurrentThread()
查詢當前執行緒是否保持著這個鎖物件,這個方法通常用在釋放鎖物件的時候,先判斷再釋放。
lock.isHeldByCurrentThread();
9. isLocked()
查詢此鎖物件是否由任意的執行緒保持著,即鎖物件是否正在被使用。
lock.isLocked();
10. lockInterruptibly()
如果當前執行緒未被終端,則可以獲取該鎖物件,如果已經被中斷了,則出現異常。
lock.lockInterruptibly();
11. Boolean tryLock()
當某執行緒呼叫該方法時,只有在呼叫時鎖物件未被另一個執行緒持有的情況下,才能夠獲取該鎖物件。
lock.tryLock();
12. Boolean tryLock(long timeout, TimeUnit unit)
如果鎖物件在給定的等待時間內沒有被另一個執行緒獲取,且當前執行緒未被中斷,則獲取該鎖物件。
lock.tryLock(3, TimeUnit.SECONDS);
(六) Condition物件的方法
1. awaitUninterruptibly()
與await()方法的區別是,當前執行緒呼叫該方法後,即使執行緒被中斷了,也不會出現異常,而await()方法被中斷時,立即會出現異常。
condition.awaitUninterruptibly();
2. awaitUntil(Time)
進入等待狀態Time時間,之後會自動喚醒。也可以由其他的執行緒來提前喚醒。
condition.awaitUntil(Time);
(七) ReentrantReadWriteLock類
1. 概述
雖然ReentrantLock類能夠實現完全互斥的功能,但是同一時刻只有一個執行緒在執行ReentrantLock.lock()後面的任務,十分低效。因此,引出了一個新的讀寫鎖ReentrantReadWriteLock類。
2. 讀鎖與寫鎖
讀寫鎖有兩個鎖,一個是與讀操作相關的鎖,稱為共享鎖;一個是與寫操作相關的鎖,稱為排它鎖。很顯然,多個讀鎖之間不是互斥的,讀鎖與寫鎖是互斥的,多個寫鎖是互斥的。
3. 讀鎖
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
lock.readLock().lock();
lock.readLock().unlock();
4. 寫鎖
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
lock.writeLock().lock();
lock.writeLock().unlock();