天天看點

# 說說我對于線程同步的發散性思考

本文在 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,一個用來觸發第二個,一個用來觸發第三個線程。”

我說道:“那這就得很多個了,萬一很多線程呢?”

小輝說道:“那就給每個線程一個清單,如果第一個線程要等待的話,就把自己加入到其中,就告訴系統說讓别人運作吧,這樣别的線程就能開始運作了,就同步了。”

我點頭。

小輝繼續說道:“這樣的話,要是别的線程也不運作,那就都等着,就卡死。”

我說道:“不太可能都不運作,可以先不考慮。”

我又說道:“可以考慮多個清單,這樣的話比如線程一要和線程三交流的話,就用第二個清單,線程一要和線程二交流的話,就用第一個清單。線程一做完了事情,要讓線程三繼續的話,就把自己放到第二個清單裡,然後讓線程三開始,線程三開始以後,做了一段事情,要交給線程一了,就把自己加到第二個清單裡,然後讓線程一開始。”

……

繼續閱讀