分析完了AQS原理,下面藉助AQS實現一個同步類,然後用這個同步類寫一下經典的三個線程循環打印。就決定叫它BLock
。
對於BLock
而言只需要對外提供兩個方法lock()
、unlock()
,那麼AQS的具體實現可以模仿ReentrantLock
託管給內部類Sync
。
class BLock {
private val sync = Sync()
fun lock() {
sync.lock()
}
fun unlock() {
sync.unlock()
}
private inner class Sync : AbstractQueuedSynchronizer() {
fun lock() = acquire(1)
override fun tryAcquire(arg: Int): Boolean {
return true
}
fun unlock() {
release(1)
}
override fun tryRelease(arg: Int): Boolean {
return true
}
}
}
lock()默認請求一個資源acquire(1)
;unlock()對應釋放資源release(1)
。接下來分別實現tryAcquire()
、tryRelease()
實現資源控制,也就是state
的值啦。
tryAcquire()
override fun tryAcquire(arg: Int): Boolean {
val s = state
if (s == 0) {
if (compareAndSetState(0, arg)) {
exclusiveOwnerThread = currentThread
return true
}
}
return false
}
獲取當前state:
- 爲0表示鎖已被釋放,cas改爲1成功後標識currentThread然後返回true
- 其它情況下返回false
但是這樣忽略了可重入的邏輯,有可能當前線程持有了鎖又再次獲取鎖,問題不大加個if else
override fun tryAcquire(arg: Int): Boolean {
val currentThread = Thread.currentThread()
val s = state
if (s == 0) {
if (compareAndSetState(0, arg)) {
exclusiveOwnerThread = currentThread
return true
}
} else if (currentThread === exclusiveOwnerThread) {
val next = s + arg
state = next
return true
}
return false
}
state爲1時判斷當前線程是否已經獲取了鎖currentThread === exclusiveOwnerThread
,已獲取state繼續+1,由此可知lock()了幾次unlock()也要對應調用才能釋放鎖。
tryRelease()
override fun tryRelease(arg: Int): Boolean {
val c: Int = state - arg
if (Thread.currentThread() !== exclusiveOwnerThread) throw IllegalMonitorStateException()
var free = false
if (c == 0) {
free = true
exclusiveOwnerThread = null
}
state = c
return free
}
state減去1
- check當前線程是否獲取了鎖
- state爲0釋放鎖,currentThread置爲null
- state不爲0返回false
寫下來其實和ReentrantLock非公平鎖的實現差不太多,接下來用BLock實現三個線程循環打印。
private fun initThread() {
val lock = BLock()
var count = 0
val maxCount = 100
Thread A@{
while (true) {
lock.lock()
if (count > maxCount) {
lock.unlock()
return@A
}
if (count % 3 == 0) {
Log.d("chenxuan----->", "A-$count")
count++
}
lock.unlock()
}
}.start()
Thread B@{
while (true) {
lock.lock()
if (count > maxCount) {
lock.unlock()
return@B
}
if (count % 3 == 1) {
Log.d("chenxuan----->", "B-$count")
count++
}
lock.unlock()
}
}.start()
Thread C@{
while (true) {
lock.lock()
if (count > maxCount) {
lock.unlock()
return@C
}
if (count % 3 == 2) {
Log.d("chenxuan----->", "C-$count")
count++
}
lock.unlock()
}
}.start()
}
check下log