在Kotlin中正确实现等待和通知
根据本文件,Kotlin不鼓励使用在Kotlin中正确实现等待和通知,kotlin,Kotlin,根据本文件,Kotlin不鼓励使用等待和通知: wait()/notify() 有效的Java项目69善意地建议优先使用并发实用程序wait()和notify()。因此,这些方法在任何类型的引用上都不可用 然而,该文件并未提出任何正确的方法 基本上,我想实现一个服务,它将读取输入数据并进行处理。如果没有输入数据,它将暂停自己,直到有人通知有新的输入数据。差不多 while (true) { val data = fetchData() processData(data)
等待
和通知
:
wait()/notify()
有效的Java项目69善意地建议优先使用并发实用程序wait()和notify()。因此,这些方法在任何类型的引用上都不可用
然而,该文件并未提出任何正确的方法
基本上,我想实现一个服务,它将读取输入数据并进行处理。如果没有输入数据,它将暂停自己,直到有人通知有新的输入数据。差不多
while (true) {
val data = fetchData()
processData(data)
if (data.isEmpty()) {
wait()
}
}
编辑:
我不想使用这些不推荐的方法(反模式),我真的想知道如何正确地做到这一点
在我的例子中,fetchData
从数据库读取数据,因此不能使用我的例子中的队列。A可以是适合您的用例的高级并发实用程序,但应用它需要了解和修改您的代码结构
其思想是,fetchData()
应该从队列中删除一个项目,如果队列为空,则将阻止执行,直到出现一个项目,从而消除代码中的.wait()
。数据的生产者应将数据导入队列
如果确实需要使用
wait
和notify
,例如,为了在低级别实现并发实用程序,可以将Kotlin对象强制转换为java.lang.object
,然后调用这些函数,如中所述。或者,写为扩展函数:
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
private fun Any.wait() = (this as java.lang.Object).wait()
通常,如果可能,您应该使用更高级别的并发实用程序 但是,如果在您的案例中没有更高级别的构造工作,则直接 替换是使用 还有一个 在那把锁上 例如,如果您的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.ReadLock
和
ReentrantReadWriteLock.WriteLock
)
请注意,withLock
是Kotlin提供的扩展函数,负责在调用提供的lambda之前/之后调用Lock.Lock()
/Lock.unlock()
。您可以使用来挂起协程,而不是阻塞线程:
val semaphore = Semaphore(1, 0)
suspend fun runFetchLoop() = withContext(Dispatchers.Default){
while (isActive) {
val data = fetchData()
processData(data)
semaphore.acquire()
if (data.isEmpty()) {
semaphore.acquire()
}
semaphore.release()
}
}
fun notifyDataAvailable() = semaphore.release()
下面是一个正在运行的示例:
然而,我更喜欢冷或热来解决这个问题。下面是一个关于伟大的罗马Elizarov的冷流和热通道的好例子您是否检查了有效的Java项目69?您可以使用Kotlin coroutines的参与者来实现您的服务。它等待项目发送到通道。更多信息:您可以将任何对象强制转换为
java.lang.object
,并轻松实现此类反模式。目前,来自协同程序的actor
已被弃用,因此这也是一个不好的选择。在我的情况下,Ad BlockingQueue不起作用,因为收到通知后,我需要检查数据库中的数据。有什么有用的吗?Adnotify
,我真的不需要使用它,我只需要找到合适的东西:-)@Vojtěch Maybe a?而不是强制转换和@Suppress,创建专用的val lock=Object()
,并使用任何synchronized(lock){lock.wait();lock.notify()}
。这是没有编译器警告的。Kotlin还添加了withLock
更高级别的函数,这使它更加出色@琼蒂森,谢谢!不知何故,我错过了标准库中with lock
的存在(我发誓我一直在寻找类似的东西)。我已经更新了使用它的答案。您仍然必须使用变量布尔值
来检查线程是否正在等待,因此对我来说,使用同步+对象@user924是什么意思?使用等待()
/通知()
和reeantlock
/条件
以及协同程序没有意义。这两种方法都会阻塞线程,这在例程中是不可接受的。我认为这个答案中的示例是错误的。有一个比赛条件。我假设notify()
是在fetchData()
返回与以前不同的内容之后调用的。如果在data.isEmpty()
之后调用notify()
,但在mutex.lock()
之前调用,则等待mutex.lock()
的协程将永远等待。@PavelČernocký。为了修复它,我用一个信号量和两个acquire调用替换了互斥。这将条件和悬架连接在一起。如果notify调用介于isEmpty条件和acquire调用之间,则不会再导致不必要的无限暂停。此修复程序还有另一个问题acquire()
/release()
必须成对提供此处不保证的内容。特别是当多次调用notifyDataAvailable()
时,它将抛出异常,因为没有信号量
允许释放。总的来说,我不认为这种方法是正确的,它肯定不能被推广。整个而的构造很糟糕data
是局部变量,由fetchData
填充,因此fetchData
应该与notifyDataAvailable
协调。