在Kotlin正确实施等待和通知

时间:2017-06-16 12:49:05

标签: kotlin

根据此文档,Kotlin不鼓励使用waitnotifyhttps://kotlinlang.org/docs/reference/java-interop.html

  

等待()/通知()

     

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

然而,该文件没有提出任何正确的方法。

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

这样的东西
while (true) {
    val data = fetchData()
    processData(data)
    if (data.isEmpty()) {
        wait()
    }
}

编辑:

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

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

3 个答案:

答案 0 :(得分:19)

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

但是,如果没有高级构造在您的情况下工作,则直接 更换是使用一个 ReentrantLock和一个 Condition 在那个锁上。

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

private Object lock = new Object();

...

synchronized(lock) {
    ...
    lock.wait();
    ...
    lock.notify();
    ...
    lock.notifyAll();
    ...
}

您可以将其更改为以下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()
    ...
}

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

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

答案 1 :(得分:14)

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

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

如果确实需要使用waitnotify,例如为了在低级实现并发实用程序,您可以将Kotlin对象强制转换为java.lang.Object并在之后调用这些函数,如the language reference中所述。或者,写为扩展函数:

@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
private fun Any.wait() = (this as java.lang.Object).wait()

答案 2 :(得分:0)

您可以使用kotlin Mutex来暂停协程而不是阻塞线程:

Intents.init()

以下是一个运行示例:https://pl.kotl.in/Q6V0X8DvL

但是我更喜欢使用 Flow hot Channel来解决此问题。 article这里是关于伟大的罗马伊莱莎洛夫的冷流和热通道的很好的{@ 3}