android 多線程 — reentrantLock 重入鎖

reentrantLock 、 condition 是 JAVA 1.6 時(shí)推出的,也是用來(lái)實(shí)現(xiàn)多線程同步的,和 synchronized 干的事一樣,用法頁(yè)差不多,但是比 synchronized 要靈活

其中 reentrantLock 叫重入鎖,condition 是阻塞條件,我們直接啊看用法來(lái)了解這2個(gè)類

實(shí)現(xiàn)鎖的功能

public class MyService {

    private Lock lock = new ReentrantLock();

    public void testMethod() {
        lock.lock();
        for (int i = 0; i < 5; i++) {
            System.out.println("ThreadName=" + Thread.currentThread().getName()
                    + (" " + (i + 1)));
        }
        lock.unlock();
    }
}

synchronized 因?yàn)楸旧硎顷P(guān)鍵字,只能實(shí)現(xiàn)標(biāo)記,本身不含鎖,需要我們指定對(duì)象鎖。而新的 API ReentrantLock 本身就是把鎖,不用再依托別人了。

ReentrantLock 在使用上類似于 synchronized 的同步代碼塊,我們直接在需要的位置, new 一個(gè) ReentrantLock 鎖出來(lái),然后 lock() 就能鎖定同步,unlock() 就能解鎖同步,注意unlock() 方法推薦寫(xiě)在 finnaly 里面

Condition 來(lái)阻塞線程并釋放鎖

public class MyService {

    private Lock lock = new ReentrantLock();
    private Condition condition=lock.newCondition();
    public void testMethod() {
        
        try {
            lock.lock();
            System.out.println("開(kāi)始wait");
            condition.await();
            for (int i = 0; i < 5; i++) {
                System.out.println("ThreadName=" + Thread.currentThread().getName()
                        + (" " + (i + 1)));
            }
        } catch (InterruptedException e) {
            // TODO 自動(dòng)生成的 catch 塊
            e.printStackTrace();
        }
        finally
        {
            lock.unlock();
        }
    }
}

Condition 的 await() 會(huì)阻塞當(dāng)前線程,并釋放鎖、signal() 方法喚醒 wait 阻塞的線程。

Condition.awiat() = Object.wait()
Condition.signal() = Object.notify()
Condition.signalAll() = Object.notifyAll()

reentrantLock 和 condition 都是成對(duì)出現(xiàn),一個(gè) reentrantLock 里面可以有多個(gè) condition 阻塞條件對(duì)象,需要知道的是 conditionA await 阻塞的線程對(duì)象會(huì)放在這個(gè) conditionA 的阻塞隊(duì)列里,也只能由 conditionA signalAll 喚醒。換一個(gè) condition 對(duì)象 conditionB 是不管用的

線程池的阻塞隊(duì)列里面大量使用了 reentrantLock ,condition ,一般我們直接用 reentrantLock 、 condition 的時(shí)候比較少,雖然 reentrantLock 的性能比 synchronized 要好,但是在使用上沒(méi)有 synchronized 方便啊,synchronized 關(guān)鍵字乙方就完了,我們就不用管了。不過(guò) reentrantLock 、 condition 的 API 我們要熟,很多時(shí)候看別人的代碼時(shí)會(huì)用到。

ReentrantLock類的方法


  • getHoldCount()
    查詢當(dāng)前線程保持此鎖的次數(shù),也就是執(zhí)行此線程執(zhí)行l(wèi)ock方法的次數(shù)

  • getQueueLength()
    返回正等待獲取此鎖的線程估計(jì)數(shù),比如啟動(dòng)10個(gè)線程,1個(gè)線程獲得鎖,此時(shí)返回的是9

  • getWaitQueueLength(Condition condition)
    返回等待與此鎖相關(guān)的給定條件的線程估計(jì)數(shù)。比如10個(gè)線程,用同一個(gè)condition對(duì)象,并且此時(shí)這10個(gè)線程都執(zhí)行了condition對(duì)象的await方法,那么此時(shí)執(zhí)行此方法返回10

  • hasWaiters(Condition condition)
    查詢是否有線程等待與此鎖有關(guān)的給定條件(condition),對(duì)于指定contidion對(duì)象,有多少線程執(zhí)行了condition.await方法

  • hasQueuedThread(Thread thread)
    查詢給定線程是否等待獲取此鎖

  • hasQueuedThreads()
    是否有線程等待此鎖

  • isFair()該鎖是否公平鎖

  • isHeldByCurrentThread() 當(dāng)前線程是否保持鎖鎖定,線程的執(zhí)行l(wèi)ock方法的前后分別是false和true

  • isLock()
    此鎖是否有任意線程占用

  • lockInterruptibly()
    如果當(dāng)前線程未被中斷,獲取鎖

  • tryLock()
    嘗試獲得鎖,僅在調(diào)用時(shí)鎖未被線程占用,獲得鎖

  • tryLock(long timeout TimeUnit unit)
    如果鎖在給定等待時(shí)間內(nèi)沒(méi)有被另一個(gè)線程保持,則獲取該鎖

Lock類分公平鎖和不公平鎖,公平鎖是按照加鎖順序來(lái)的,非公平鎖是不按順序的,也就是說(shuō)先執(zhí)行l(wèi)ock方法的鎖不一定先獲得鎖

reentrantLock 的確要靈活的多,我們不用使用別的鎖了,在想要的位置直接 new 一把鎖,阻塞的條件可以有多個(gè),可以實(shí)現(xiàn)復(fù)雜的操作,這是阻塞隊(duì)列的核心。另外 reentrantLock 可以使用 tryLock 嘗試獲得鎖,可以避免一直卡在這里競(jìng)爭(zhēng)鎖。reentrantLock 對(duì)于高玩來(lái)說(shuō)是個(gè)可以極大發(fā)揮的東西,但是對(duì)于 coder 們來(lái)說(shuō),還是在項(xiàng)目縱謹(jǐn)慎使用。

下面是一個(gè)對(duì) ReentrantLock 中肯的評(píng)價(jià)

既然如此,我們什么時(shí)候才應(yīng)該使用 ReentrantLock 呢?答案非常簡(jiǎn)單 —— 在確實(shí)需要一些 synchronized 所沒(méi)有的特性的時(shí)候,比如時(shí)間鎖等候、可中斷鎖等候、無(wú)塊結(jié)構(gòu)鎖、多個(gè)條件變量或者鎖投票。 ReentrantLock 還具有可伸縮性的好處,應(yīng)當(dāng)在高度爭(zhēng)用的情況下使用它,但是請(qǐng)記住,大多數(shù) synchronized 塊幾乎從來(lái)沒(méi)有出現(xiàn)過(guò)爭(zhēng)用,所以可以把高度爭(zhēng)用放在一邊。我建議用 synchronized 開(kāi)發(fā),直到確實(shí)證明 synchronized 不合適,而不要僅僅是假設(shè)如果使用 ReentrantLock “性能會(huì)更好”。請(qǐng)記住,這些是供高級(jí)用戶使用的高級(jí)工具。(而且,真正的高級(jí)用戶喜歡選擇能夠找到的最簡(jiǎn)單工具,直到他們認(rèn)為簡(jiǎn)單的工具不適用為止。)。一如既往,首先要把事情做好,然后再考慮是不是有必要做得更快。

參考資料:


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 作者: 一字馬胡 轉(zhuǎn)載標(biāo)志 【2017-11-03】 更新日志 前言 在java中,鎖是實(shí)現(xiàn)并發(fā)的關(guān)鍵組件,多個(gè)...
    一字馬胡閱讀 44,189評(píng)論 1 32
  • ?既然java內(nèi)置了synchronized,為什么還要出現(xiàn)lock呢??由于synchronized的并發(fā)是阻塞...
    扈扈哈嘿閱讀 917評(píng)論 0 1
  • Java-Review-Note——4.多線程 標(biāo)簽: JavaStudy PS:本來(lái)是分開(kāi)三篇的,后來(lái)想想還是整...
    coder_pig閱讀 1,677評(píng)論 2 17
  • PCA 算法主要是把高維度的數(shù)據(jù)降為低維度數(shù)據(jù)。典型地應(yīng)用包括數(shù)據(jù)壓縮和數(shù)據(jù)可視化。本文介紹 PCA 算法及其典型...
    kamidox閱讀 4,983評(píng)論 6 12
  • 1 在佛山學(xué)習(xí)了6天,今天決定回去,上午10:30看票,最合適的13:50廣州到長(zhǎng)沙,歷經(jīng)7小時(shí)22分(還是要省學(xué)...
    橘子778閱讀 230評(píng)論 0 2