如何解决同步和withContext
我有以下课程:
class SdkWrapper(private val sdk: Sdk) {
private var inited = false
suspend fun doSomething() = withContext(Dispatchers.IO) {
if (inited.not()) init()
useSdk()
}
private fun init() {
// takes a long time
sdk.init()
inited = true
}
// has to be done asynchronously
// sdk.init() has to have been called before using this
private fun useSdk() {
}
}
class Sdk {
// must only be done once
fun init() {}
}
在执行useSdk()
之前,我必须先致电sdk.init()
,但是sdk.init()
只能被调用一次,不能再被调用。
在我当前的解决方案中,如果doSomething
被快速调用两次(第二次发生在sdk.init()
仍在运行时),我会两次调用sdk.init()
,因为inited: Boolean
是仍然false
。
如果我将inited
的分配上调为:
private fun init() {
inited = true
sdk.init()
}
和doSomething()
被快速调用两次,第二次调用将在完成其init()
之前使用sdk。
我试图用以下方法解决这个问题:
suspend fun doSomething() = synchronized(this){
withContext(Dispatchers.IO) {
if (inited.not()) init()
useSdk()
}
}
但是在IntelliJ中收到错误:
withContext悬浮点位于关键部分
我认为synchronized
在这里还是行不通的,因为我们移出了主线程,并且doSomething()
在withContext
块仍在运行时完成了吗?
我该如何解决基本上是doSomething()
一次只能运行一次的问题?
解决方法
您可以使用Mutex代替synchronized {...}
:
class SdkWrapper(private val sdk: Sdk) {
...
private val mutex = Mutex()
suspend fun doSomething() = mutex.withLock {
withContext(Dispatchers.IO) {
if (inited.not()) init()
useSdk()
}
}
...
}
您可以查看有关协程和互斥here的官方文档。