1. 程式人生 > 其它 >【Java學習筆記(八十三)】之 ReentrantLock類,Condition類,ReentrantReadWriteLock類

【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();