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
關鍵字同樣,線程之間執行的順序時隨機的。線程
關鍵字synchronized
與wait()
和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
實現代碼以下: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)複製代碼
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 - 進入沒法被打斷的等待狀態