【问题标题】:Synchronized and withContext同步和 withContext
【发布时间】:2020-10-09 09:09:11
【问题描述】:

我有以下课程:

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() 一次只能运行一次?

【问题讨论】:

    标签: kotlin synchronized kotlin-coroutines


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 2021-01-02
      • 2017-07-24
      • 2020-10-22
      • 2019-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-13
      相关资源
      最近更新 更多