kotlin - 在 Kotlin 中锁定互斥锁的正确方法

标签 kotlin kotlin-coroutines

我想使用 Kotlin Coroutines 实现一个简单的线程安全 Buffer,因为项目中已经使用了协程。

缓冲区将在多线程和单线程上下文中使用,因此使用 suspend fun getMostRecentData() 似乎不太合理(请参见下面的代码)。

这就是我目前所拥有的。事实上,我必须编写所有代码来锁定互斥锁,这让我想知道我是否做错了什么。

无论如何,这是代码:

class SafeBuffer(
    private val dispatcher: CoroutineDispatcher,
    private val bufferSize: Int
    ) {

    private val buffer = LinkedList<MyDataType>()
    private val mutex = Mutex()

    val size: Int
        get() = buffer.size

   // First approach: make a suspend fun
   // Not great because I will need a runBlocking{} statement somewhere, every time I want to access the buffer
   suspend fun getMostRecentData() : MyDataType? {
        mutex.withLock {
            return if (buffer.isEmpty()) null else buffer.last
        }
    }

   // Second approach: use a runBlocking block inside the function
   // Seems like it is missing the purpose of coroutines, and I'm not 
   // sure it is actually thread safe if other context is used somehow?
   fun getMostRecentData() : MyDataType? {
        runBlocking(dispatcher) {
            mutex.withLock {
                return if (buffer.isEmpty()) null else buffer.last
            }
        }
    }

    /**** More code ****/
    (...)

}

那么实现这一目标的最惯用/最优雅的方式是什么?

最佳答案

扩展我的评论,我认为让缓冲区类只公开一个suspend fun 是惯用的,因为类的使用者将负责弄清楚他们想如何使用它(通过 runBlocking 或来自另一个协程)。如果您发现此用例经常出现,惯用的方法可能是在 SafeBuffer 上添加一个扩展函数来提供此功能。

扩展函数在协程 API 中随处可见。在您的代码示例中,甚至 Mutex.withLock 也被定义为扩展函数。

class SafeBuffer(...) {

    private val buffer = LinkedList<MyDataType>()
    private val mutex = Mutex()

    suspend fun getMostRecentData() : MyDataType? =
        mutex.withLock {
            if (buffer.isEmpty()) null else buffer.last
        }
}

fun SafeBuffer.getMostRecentDataBlocking(): MyDataType? =
    runBlocking {
        getMostRecentData()
    }

关于kotlin - 在 Kotlin 中锁定互斥锁的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67321436/

相关文章:

android - 尝试授权 Health Kit 时应用卡住

android - 使用 withContext 方法在 kotlin 协程中进行 try-catch

android - 在 Dispatcher.Main 的上下文中执行网络任务

kotlin - runBlocking 协程不会阻止 GlobalScope.launch (?)

firebase - 如何使用 Kotlin 协程运行 Firebase 事务?

android - Android (Kotlin) 中仅将最后一个元素添加到 RecyclerView

android - 使用camera2 API createCaptureSession后,Android无法仅播放视频音频

java - 使用 viewModels 从 ChildFragment 访问 ParentFragment 中的 ViewModel

android - "Cannot access database on the main thread since it may potentially lock the UI for a long period of time"启动协程时出错

scala - Gradle Kotlin DSL Scala和想法