Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Kotlin中正确实现等待和通知_Kotlin - Fatal编程技术网

在Kotlin中正确实现等待和通知

在Kotlin中正确实现等待和通知,kotlin,Kotlin,根据本文件,Kotlin不鼓励使用等待和通知: wait()/notify() 有效的Java项目69善意地建议优先使用并发实用程序wait()和notify()。因此,这些方法在任何类型的引用上都不可用 然而,该文件并未提出任何正确的方法 基本上,我想实现一个服务,它将读取输入数据并进行处理。如果没有输入数据,它将暂停自己,直到有人通知有新的输入数据。差不多 while (true) { val data = fetchData() processData(data)

根据本文件,Kotlin不鼓励使用
等待
通知

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不起作用,因为收到通知后,我需要检查数据库中的数据。有什么有用的吗?Ad
notify
,我真的不需要使用它,我只需要找到合适的东西:-)@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
协调。