# 說說我對于線程同步的發(fā)散性思考
本文在 https://wkmcyz.notion.site/2cbaab3404c04513b16f40f48e0c9cb7 閱讀體驗更好。
我和小輝一起散步,小輝忽然說他最近要寫一個實現(xiàn)鎖能力的機制,可以讓 java 各個線程通過這個機制比較好地實現(xiàn)同步。
我問他:“那用法是什么?”
小輝說:“我這個系統(tǒng),給別人調(diào)用的時候,別人只需要傳遞一個閉包就可以了,我會負責確保多個線程調(diào)用相同的閉包的時候,每個閉包都不是并行的。”
我一想,這個應該比較好實現(xiàn),只需要本地維護一個閉包到執(zhí)行線程列表的對應關系就可以了,有新的線程到來的時候,就判斷一下當前的閉包是不是正在運行,如果有的話,就等待;如果沒有的話,就把這個當做第一個來運行。kotlin 代碼表示的話,就是 :
val map = HashMap<runnable : Array<Thread>>
fun runSynchronously(thread : Thread , runnable : Runnable) {
if(map.contains(runnable)) {
map[runnable].add(thread)
} else {
map[runnable] = new ArrayList<Thread>(thread)
runnable.run()
}
}
private fun runFirst(runnable) {
val thread = map[runnable].first()
runnable.runInThread(thread)
runRunnableNext()
}
private fun runRunnableNextInNext(runnable :Runnable){
map[runnable].removeFirst()
runFirst(runnable)
}
然后我想了想,想到了一個問題:這樣的話,我線程要么不執(zhí)行,進入等待;要么就直接執(zhí)行。那如果兩個線程執(zhí)行的時候想交替執(zhí)行怎么辦?
小輝說道:“這個是個好問題,需要先想一想。”
我說:“任務 A 如果要在中間讓任務 B接著做什么的話,就需要任務 A 先完成,就是說這時候任務 A 會有一個分支,從 runnable 中 return,然后任務 B 就可以接著執(zhí)行了。”
小輝說道:“不過這樣的話,任務 B 開始執(zhí)行的時候,怎么知道該執(zhí)行最初的邏輯還是任務 A 執(zhí)行了一部分以后的邏輯呢?”
我說:“那就加狀態(tài)變量,任務 A 完成以后,把狀態(tài)變量從 0 設置為 1 , 任務 B 開始的時候判斷一下當前的狀態(tài),如果是 1 的話,就按照 1 的邏輯處理,然后再改為 2,任務 B 再退出,任務 A 再開始,判斷狀態(tài)是 3,就執(zhí)行一個更新的邏輯。”
小輝說:“好像也不是不行啊……”然后又說道:“就是有點復雜了,這樣的話代碼沒法寫了。全是邏輯判斷。”
我說:“還好呀,可以寫成 switch(status) 的形式”
小輝說道:“那我這樣也行啊。你看,系統(tǒng)接受 runnable 以后,交給 runnable 一個 callback,runnable 可以在代碼里面執(zhí)行這個 callback,這個 callback 執(zhí)行的結果就是讓另一個線程來執(zhí)行 runnable。”
我一聽,覺得很有意思,好像確實可行。但是兩個還好,如果有三個的話,豈不是亂了套了,于是提出了這個問題。
小輝說道:“那就用倆 callback,一個用來觸發(fā)第二個,一個用來觸發(fā)第三個線程。”
我說道:“那這就得很多個了,萬一很多線程呢?”
小輝說道:“那就給每個線程一個列表,如果第一個線程要等待的話,就把自己加入到其中,就告訴系統(tǒng)說讓別人運行吧,這樣別的線程就能開始運行了,就同步了。”
我點頭。
小輝繼續(xù)說道:“這樣的話,要是別的線程也不運行,那就都等著,就卡死。”
我說道:“不太可能都不運行,可以先不考慮。”
我又說道:“可以考慮多個列表,這樣的話比如線程一要和線程三交流的話,就用第二個列表,線程一要和線程二交流的話,就用第一個列表。線程一做完了事情,要讓線程三繼續(xù)的話,就把自己放到第二個列表里,然后讓線程三開始,線程三開始以后,做了一段事情,要交給線程一了,就把自己加到第二個列表里,然后讓線程一開始。”
……
浙公網(wǎng)安備 33010602011771號