在Kotlin正确实施等待和通知

Voj*_*ěch 15 kotlin

根据这个文件,在Kotlin中使用waitnotify不鼓励:https://kotlinlang.org/docs/reference/java-interop.html

等待()/通知()

有效的Java Item 69建议更喜欢并发实用程序来wait()和notify().因此,这些方法不适用于Any类型的引用.

但是,该文件没有提出任何正确的方法.

基本上,我想实现一个服务,它将读取输入数据并处理它们.如果没有输入数据,它将暂停,直到有人通知有新的输入数据.就像是

while (true) {
    val data = fetchData()
    processData(data)
    if (data.isEmpty()) {
        wait()
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

我不想使用这些不推荐的方法(反模式),我真的想知道如何正确地做到这一点.

在我的情况下fetchData从数据库中读取数据,因此在我的情况下不能使用队列.

Lau*_*ves 24

通常,您应该尽可能使用更高级别的并发实用程序.

但是,如果没有更高级别的构造在您的情况下工作,则直接替换是 在该锁上使用a ReentrantLock和single Condition.

例如,如果您的Java代码类似于:

private Object lock = new Object();

...

synchronized(lock) {
    ...
    lock.wait();
    ...
    lock.notify();
    ...
    lock.notifyAll();
    ...
}
Run Code Online (Sandbox Code Playgroud)

您可以将其更改为以下Kotlin:

private val lock = ReentrantLock()
private val condition = lock.newCondition()

lock.withLock {           // like synchronized(lock)
    ...
    condition.await()     // like wait()
    ...
    condition.signal()    // like notify()
    ...
    condition.signalAll() // like notifyAll()
    ...
}
Run Code Online (Sandbox Code Playgroud)

虽然这稍微冗长一些,但条件确实提供了一些额外的灵活性,因为你可以在一个锁上有多个条件,还有其他类型的锁(特别是ReentrantReadWriteLock.ReadLockReentrantReadWriteLock.WriteLock).

注意,这withLock是一个Kotlin提供的扩展函数,负责调用Lock.lock()/ Lock.unlock()调用提供的lambda之前/之后.

  • Kotlin 还添加了更高级别的 `withLock` 函数,这使它变得更好! (2认同)
  • @JonTirsen 谢谢!不知何故,我错过了标准库中“withLock”的存在(我发誓我会寻找类似的东西)。我已经更新了答案以使用它。 (2认同)
  • 将“wait()”/“notify()”和“ReeantrantLock”/“Condition”与协程一起使用是没有意义的。这两种方法都会阻塞线程,这在 Couroutines 中是不可接受的。 (2认同)
  • 对协程不友好。 (2认同)

hot*_*key 15

BlockingQueue对于您的用例,A 可以是合适的高级并发实用程序,但应用它需要了解和修改代码结构.

我们的想法是,fetchData()应该.take()从队列中的项目,如果队列为空,这将阻止执行,直到出现一个项目,它消除了.wait()在你的代码.数据的生产者应该.put(t)将数据放入队列中.


如果你真的需要使用waitnotify,例如在低级实现并发实用程序,你可以将Kotlin对象转换为java.lang.Object并在之后调用这些函数,如语言参考中所述.或者,写为扩展函数:

@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
private fun Any.wait() = (this as java.lang.Object).wait()
Run Code Online (Sandbox Code Playgroud)

  • 创建专用的“val lock=Object()”,并使用任何“synchronized(lock){ lock.wait();”,而不是强制转换和@Suppress。lock.notify()}` 对此。这是没有编译器警告的。 (2认同)