Java多線程筆記(四)

Lock的使用

前言


這是java多線程基礎理論知識的第6篇文章,預計這一系列的分享還有2篇。今天要分享的內容是進階版的線程鎖,之前的線程鎖主要是synchronized關鍵字的方法或者語句塊,這種用法比較生澀和不友好;本章推薦使用Lock對象來替換synchronized,因為Lock類有很多獨特的優(yōu)勢,而且還有助于學習并發(fā)包中的源碼。

主要內容如下:

線程間通信

ReentrantLock類


ReentrantLock

聲明方式如下:

private Lock lock = new ReentrantLock();

使用方式如下:

//程序片段

try{
    //獲得鎖
    lock.lock();
    ...

}catch(InterruptedException e){
    e.printStackTrace();
}finally {
    //釋放鎖
    lock.unlock();
}

調用lock.lock()代碼的線程就持有了“對象監(jiān)視器”,其他線程只有等待鎖被釋放時再次爭搶。和synchronized關鍵字一樣,線程簡間的執(zhí)行順序是隨機的。

Conditon的使用

關鍵字synchronized與wait()和notify()/notifyAll()方法相結合可以實現等待/通知模式。類ReentrantLock也具有相同的功能,但需要借助Condition對象,該對象支持多路通知功能,就是在一個Lock對象里可以創(chuàng)建多個Condition(對象監(jiān)視器)實例,線程對象可以注冊在指定的Condition中,從而可以有選擇地進行線程通知,在線程調度上更加靈活。

聲明方式如下:

private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();

使用方式如下:

try{
    
    lock.lock();
    ...
    //等待
    condition.await();
    ...

}catch(InterruptedException e){
    e.printStackTrace();
}finally {
    lock.unlock();
}

注意,在condition.await()和condition.signal()方法調用前必須調用lock.lock()方法獲得同步監(jiān)視器。

總結:

  1. Object類中的wait()(代碼行處釋放鎖)方法相當于Condition類中的await()方法。
  2. Object類中的wait(long timeout)方法相當于Condition類中的await(long time,TimeUnit unit)方法。
  3. Object類中的notify()(執(zhí)行完釋放鎖)方法相當于Condition類中的signal()方法。
  4. Object類中的notifyAll()方法相當于Condition類中的signalAll()方法。
公平鎖與非公平鎖
鎖的分類

  • FIFO:先來先得,先進先出。
  • 搶占機制:隨機獲得鎖。

使用方式(true為公平鎖,false為非公平鎖):

lock = new ReentrantLock(boolean)

公平鎖的執(zhí)行結果是呈基本有序的,不是完全有序;非公平鎖的執(zhí)行結果是基本亂序的。

方法大總結

這里用表格列舉一下,lock經常使用的方法。

方法名 參數 描述
getHoldCount / 查詢當前線程保持此鎖定的個數,也就是調用lock()方法的個數。
getQueueLength / 返回正等待獲取此鎖定的線程估計數。
getWaitQueueLength Condition 等待與此鎖定相關的給定條件Condition的線程估計數 。
hasQueuedThread Thread 查詢指定的線程是否等待獲取此鎖。
hasQueuedThreads / 查詢是否有線程等待獲取此鎖。
hasWaiters Condition 查詢是否有線程正在等待與此鎖有關的Condition條件。
isFair / 判斷是不是公平鎖 ,ReentrantLock默認使用非公平鎖。
isHeldByCurrentThread / 查詢當前線程是否保持此鎖定。
isLocked / 查詢此鎖定是否由任意線程保持。
lockInterruptibly / 如果當前線程未被中斷,則獲取鎖定;如果中斷則拋出異常。
tryLock / 僅僅在調用時鎖定未被另一個線程保持的鎖。
tryLock long,TimeUnit 如果鎖在給定的時間內沒有被另一個線程保持,且當前線程未被中斷,則獲取該鎖定。
awaitUninterruptibly / 忽略中斷的await方法,不拋出異常。
awaitUntil 時間戳 線程在等待時間到達前,可以被其他線程提前喚醒的await方法。

ReentrantReadWriteLock類


ReentrantLock類具有完全互斥的效果,即同一時間只能有同一個線程在執(zhí)行ReentrantLock.lock()方法后面的任務。這樣做雖然很安全,但是效率很低下,這里介紹一種讀寫鎖ReentrantReadWriteLock類,讀寫鎖表示有兩個鎖,一個是讀相關操作的鎖,也稱共享鎖;一個是寫相關操作的鎖,也稱排他鎖。

共享鎖聲明方式如下:

lock.readLock().lock()

lock.readLock().unlock()

排他鎖聲明方式如下:

lock.writeLock().lock()

lock.writeLock().unlock()

讀讀共享

共享鎖允許多個線程同時執(zhí)行l(wèi)ock()方法后面的代碼。

寫寫互斥

互斥鎖同一時間只允許一個線程執(zhí)行l(wèi)ock()方法后面的代碼。

讀寫互斥

讀寫操作是互斥的,讀完之后才能寫。

寫讀互斥

寫讀操作是互斥的,寫完之后才能讀。只要出現寫操作鎖,就都是互斥的。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容