同步和 withContext

Synchronized and withContext

我有以下 class:

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() 仍然 运行ning 时),我会调用 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 中收到错误:

the withContext suspension point is inside a critical section

我假设 synchronized 无论如何都不会在这里工作,因为我们离开了主线程并且 doSomething() 完成了,而 withContext 块仍然是 运行宁?

我如何解决手头的问题,基本上是:doSomething() 应该一次只 运行 一次?

您可以使用互斥锁代替 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