本文在 https://wkmcyz.notion.site/2cbaab3404c04513b16f40f48e0c9cb7 閱讀體驗更好。
我和小輝一起散步,小輝忽然說他最近要寫一個實作鎖能力的機制,可以讓 java 各個線程通過這個機制比較好地實作同步。
我問他:“那用法是什麼?”
小輝說:“我這個系統,給别人調用的時候,别人隻需要傳遞一個閉包就可以了,我會負責確定多個線程調用相同的閉包的時候,每個閉包都不是并行的。”
我一想,這個應該比較好實作,隻需要本地維護一個閉包到執行線程清單的對應關系就可以了,有新的線程到來的時候,就判斷一下目前的閉包是不是正在運作,如果有的話,就等待;如果沒有的話,就把這個當做第一個來運作。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)
}
然後我想了想,想到了一個問題:這樣的話,我線程要麼不執行,進入等待;要麼就直接執行。那如果兩個線程執行的時候想交替執行怎麼辦?
小輝說道:“這個是個好問題,需要先想一想。”
我說:“任務 A 如果要在中間讓任務 B接着做什麼的話,就需要任務 A 先完成,就是說這時候任務 A 會有一個分支,從 runnable 中 return,然後任務 B 就可以接着執行了。”
小輝說道:“不過這樣的話,任務 B 開始執行的時候,怎麼知道該執行最初的邏輯還是任務 A 執行了一部分以後的邏輯呢?”
我說:“那就加狀态變量,任務 A 完成以後,把狀态變量從 0 設定為 1 , 任務 B 開始的時候判斷一下目前的狀态,如果是 1 的話,就按照 1 的邏輯處理,然後再改為 2,任務 B 再退出,任務 A 再開始,判斷狀态是 3,就執行一個更新的邏輯。”
小輝說:“好像也不是不行啊……”然後又說道:“就是有點複雜了,這樣的話代碼沒法寫了。全是邏輯判斷。”
我說:“還好呀,可以寫成
switch(status)
的形式”
小輝說道:“那我這樣也行啊。你看,系統接受 runnable 以後,交給 runnable 一個 callback,runnable 可以在代碼裡面執行這個 callback,這個 callback 執行的結果就是讓另一個線程來執行 runnable。”
我一聽,覺得很有意思,好像确實可行。但是兩個還好,如果有三個的話,豈不是亂了套了,于是提出了這個問題。
小輝說道:“那就用倆 callback,一個用來觸發第二個,一個用來觸發第三個線程。”
我說道:“那這就得很多個了,萬一很多線程呢?”
小輝說道:“那就給每個線程一個清單,如果第一個線程要等待的話,就把自己加入到其中,就告訴系統說讓别人運作吧,這樣别的線程就能開始運作了,就同步了。”
我點頭。
小輝繼續說道:“這樣的話,要是别的線程也不運作,那就都等着,就卡死。”
我說道:“不太可能都不運作,可以先不考慮。”
我又說道:“可以考慮多個清單,這樣的話比如線程一要和線程三交流的話,就用第二個清單,線程一要和線程二交流的話,就用第一個清單。線程一做完了事情,要讓線程三繼續的話,就把自己放到第二個清單裡,然後讓線程三開始,線程三開始以後,做了一段事情,要交給線程一了,就把自己加到第二個清單裡,然後讓線程一開始。”
……