天天看点

# 说说我对于线程同步的发散性思考

本文在 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,一个用来触发第二个,一个用来触发第三个线程。”

我说道:“那这就得很多个了,万一很多线程呢?”

小辉说道:“那就给每个线程一个列表,如果第一个线程要等待的话,就把自己加入到其中,就告诉系统说让别人运行吧,这样别的线程就能开始运行了,就同步了。”

我点头。

小辉继续说道:“这样的话,要是别的线程也不运行,那就都等着,就卡死。”

我说道:“不太可能都不运行,可以先不考虑。”

我又说道:“可以考虑多个列表,这样的话比如线程一要和线程三交流的话,就用第二个列表,线程一要和线程二交流的话,就用第一个列表。线程一做完了事情,要让线程三继续的话,就把自己放到第二个列表里,然后让线程三开始,线程三开始以后,做了一段事情,要交给线程一了,就把自己加到第二个列表里,然后让线程一开始。”

……

继续阅读