Java多線程之Lock的使用(一)

Java多線程中,可使用synchronized關鍵字實現線程之間同步互斥,JDK1.5中新增長了ReentrantLock類也能夠達到一樣的效果,而且更增強大。多線程

如何使用

class MyService {
   private var lock: Lock = ReentrantLock()
   fun testMethod() {
       lock.lock() //獲取鎖
       for (i in 1..5) {
           println("ThreadName is ${Thread.currentThread().name} $i")
       }
       lock.unlock()   //釋放鎖
   }
}複製代碼

如代碼所示,調用ReentrantLock對象的lock()方法獲取鎖,調用unlock()方法釋放鎖。spa

調用lock.lock()代碼的線程就持有了「對象監視器」,其餘線程就只有等待鎖被釋放時再次爭搶。效果和synchronized關鍵字同樣,線程之間執行的順序時隨機的。線程

使用Condition實現等待/通知

關鍵字synchronizedwait()notify()/notifyAll()方法結合能夠實現等待/通知模式,類ReentrantLock也能夠實現一樣的功能,但須要藉助於Condition對象。code

Condition類是JDK1.5中出現的技術,使用它有更好的靈活性,好比能夠實現多路通知功能,也就是在一個Lock對象裏面建立多個Condition(即對象監視器)實例,線程對象能夠註冊在指定的Condition中,從而能夠有選擇的進行線程通知。對象

在使用notify()方法進行通知的時候,被通知的線程是由JVM隨機選擇的。使用ReentrantLock結合Condition是能夠實現「選擇性通知」的。get

synchronized至關於整個Lock對象中只有一個單一的Condition對象,全部線程都註冊在它一個對象上。同步

實現代碼以下:it

class MyService {

    private var lock: Lock = ReentrantLock()

    private var condition: Condition = lock.newCondition()

    fun await() {
        try {
            lock.lock()
            println("await時間爲: ${System.currentTimeMillis()}")
            condition.await()
        } catch(e: InterruptedException) {
            e.printStackTrace()
        } finally {
            lock.unlock()
        }
    }

    fun signal() {
        try {
            lock.lock()
            println("signal時間爲:${System.currentTimeMillis()}")
            condition.signal()
        } finally {
            lock.unlock()
        }
    }
}複製代碼

Object類中的wait()方法至關於Condition類中的await()方法,Object類中的notify至關於Condition中的signal()io

使用多個Condition實現通知部分線程

實現代碼以下:class

class MyService {

    private var lock: Lock = ReentrantLock()

    private var conditionA: Condition = lock.newCondition()
    private var conditionB: Condition = lock.newCondition()

    fun awaitA() {
        try {
            lock.lock()
            println("begin awaitA時間爲:${System.currentTimeMillis()} ThreadName = ${Thread.currentThread().name}")
            conditionA.await()
            println("end awaitA時間爲:${System.currentTimeMillis()} ThreadName = ${Thread.currentThread().name}")
        } catch(e: InterruptedException) {
            e.printStackTrace()
        } finally {
            lock.unlock()
        }
    }

    fun awaitB() {
        try {
            lock.lock()
            println("begin awaitB時間爲:${System.currentTimeMillis()} ThreadName = ${Thread.currentThread().name}")
            conditionB.await()
            println("end awaitB時間爲:${System.currentTimeMillis()} ThreadName = ${Thread.currentThread().name}")
        } catch(e: InterruptedException) {
            e.printStackTrace()
        } finally {
            lock.unlock()
        }
    }

    fun signalAll_A() {
        try {
            lock.lock()
            println("signalAll_A時間爲:${System.currentTimeMillis()} ThreadName = ${Thread.currentThread().name}")
            conditionA.signalAll()
        } finally {
            lock.unlock()
        }
    }

    fun signalAll_B() {
        try {
            lock.lock()
            println("signalAll_B時間爲:${System.currentTimeMillis()} ThreadName = ${Thread.currentThread().name}")
            conditionB.signalAll()
        } finally {
            lock.unlock()
        }
    }
}複製代碼

公平鎖與非公平鎖

鎖Lock分爲「公平鎖」和「非公平鎖」,公平鎖表示線程獲取鎖的順序是按照線程加鎖的順序來分配的,即先來先得的FIFO順序。而非公平鎖就是一種獲取鎖的搶佔機制,是隨機得到鎖的。

  • 建立公平鎖:

    var lock: Lock = ReentrantLock(true)複製代碼

    or

    var lock: Lock = ReentrantLock()複製代碼
  • 建立非公平鎖:

    var lock: Lock = ReentrantLock(false)複製代碼

ReentrantLock一些經常使用的方法

  • getHolderCount():int - 查詢當前線程保持此鎖定的個數

  • getQueueLength():int - 獲取正在等待獲取此鎖定的線程估計數

    好比有5個線程,一個線程首先執行await()方法,那麼調用getQueueLength()方法的返回值是4,說明4個線程同時等待lock的釋放。

  • getWaitQueueLength(Condition):int - 返回等待與此鎖定相關的給定條件Condition的線程估計數

    好比有5個線程,每一個線程都執行了同一個Condition對象的await()方法,則調用getWaitQueueLength()方法時返回5

  • hasQueuedThread(Thread):boolean - 查詢指定的線程是否正在等待獲取此鎖定

  • hasQueuedThreads():boolean - 查詢是否有線程正在等待獲取此鎖定

  • hasWaiters(Condition):boolean - 查詢是否有線程正在等待與此鎖定有關的Condition條件

  • isFair():boolean - 判斷是否是公平鎖

  • isHeldByCurrentThread():boolean - 查詢當前線程是否保持鎖定

  • isLocked():boolean - 查詢此鎖定是否由任意線程保持

  • lockInterruptibly():void - 若是當前線程未被中斷,則獲取鎖定,若是已經被中斷則出現異常

  • tryLock():boolean - 僅在調用時鎖定未被另外一個線程保持的狀況下,才獲取該鎖定

  • tryLock(long,TimeUnit):boolean - 若是鎖定在給定等待時間內沒有被另外一個線程保持,且當前線程未被中斷,則獲取該鎖定

  • awaitUnintterruptibly():void - 進入沒法被打斷的等待狀態

相關文章
相關標籤/搜索