同步和 withContext

asc*_*sco 2 synchronized kotlin kotlin-coroutines

我有以下课程:

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() {}
}
Run Code Online (Sandbox Code Playgroud)

在我能做之前useSdk(),我必须调用sdk.init(),但sdk.init()只能调用一次,不能多次。

使用我当前的解决方案,如果doSomething快速调用两次(第二次发生在sdk.init()仍在运行时),我会调用sdk.init()两次,因为inited: Boolean仍然是false

如果我像这样移动 up 的分配inited

private fun init() {
    inited = true
    sdk.init()
}
Run Code Online (Sandbox Code Playgroud)

并且被快速调用两次,第二次调用将在其完成doSomething()之前使用 SDK 。init()

我尝试用以下方法解决这个问题:

suspend fun doSomething() = synchronized(this){
    withContext(Dispatchers.IO) {
        if (inited.not()) init()
        useSdk()
    }
}
Run Code Online (Sandbox Code Playgroud)

但在 IntelliJ 中收到错误:

withContext 挂起点位于关键部分内

我认为这synchronized在这里不起作用,因为我们离开主线程并在块仍在运行doSomething()时完成?withContext

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

Gle*_*val 15

synchronized {...}您可以使用互斥锁来代替:

class SdkWrapper(private val sdk: Sdk) {

    ...

    private val mutex = Mutex()

    suspend fun doSomething() = mutex.withLock {
        withContext(Dispatchers.IO) {
            if (inited.not()) init()
            useSdk()
        }
    }

    ...

}
Run Code Online (Sandbox Code Playgroud)

你可以在这里查看关于协程和互斥的官方文档。