Java AQS 自定義同步類

分析完了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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章