我想暂停一个kotlin协程,直到从外部调用一个方法为止,就像旧的Java object.wait()和object.notify()方法一样。我该怎么办?
此处:Correctly implementing wait and notify in Kotlin是如何使用Kotlin线程(阻塞)实现此目的的答案。在这里:Suspend coroutine until condition is true是如何使用CompleteableDeferreds做到这一点的答案,但我不想每次都必须创建一个新的CompleteableDeferred实例。
我目前正在这样做:
var nextIndex = 0
fun handleNext(): Boolean {
if (nextIndex < apps.size) {
//Do the actual work on apps[nextIndex]
nextIndex++
}
//only execute again if nextIndex is a valid index
return nextIndex < apps.size
}
handleNext()
// The returned function will be called multiple times, which I would like to replace with something like notify()
return ::handleNext
答案 0 :(得分:4)
Channels可以用于此(尽管它们更通用):
当容量为0时,它将创建RendezvousChannel。该通道根本没有任何缓冲区。仅当发送和接收调用在时间上符合(交会)时,元素才会从发送方转移到接收方,因此send暂停直到另一个协程调用receive,接收暂停直到另一个coroutine调用send。
因此创建
val channel = Channel<Unit>(0)
对于object.wait()
使用channel.receive()
,对于object.notify()
使用channel.offer(Unit)
(如果要等到其他协程send
,则使用receive
s。
对于notifyAll
,您可以改用BroadcastChannel
。
您当然可以轻松地封装它:
inline class Waiter(private val channel: Channel<Unit> = Channel<Unit>(0)) {
suspend fun doWait() { channel.receive() }
fun doNotify() { channel.offer(Unit) }
}
答案 1 :(得分:0)
为此,可以使用基本的suspendCoroutine{..}
函数,例如
class SuspendWait() {
private lateinit var myCont: Continuation<Unit>
suspend fun sleepAndWait() = suspendCoroutine<Unit>{ cont ->
myCont = cont
}
fun resume() {
val cont = myCont
myCont = null
cont.resume(Unit)
}
}
很明显,代码存在问题,例如myCont
字段未同步,预计在sleepAndWait
之前调用resume
,依此类推,希望现在能弄清楚这个想法。
kotlinx.coroutines库中的Mutex
类还有另一种解决方案。
class SuspendWait2 {
private val mutex = Mutex(locaked = true)
suspend fun sleepAndWait() = mutex.withLock{}
fun resume() {
mutex.unlock()
}
}
答案 2 :(得分:0)
我建议为此使用CompletableJob
。
我的用例:
suspend fun onLoad() {
var job1: CompletableJob? = Job()
var job2: CompletableJob? = Job()
lifecycleScope.launch {
someList.collect {
doSomething(it)
job1?.complete()
}
}
lifecycleScope.launch {
otherList.collect {
doSomethingElse(it)
job2?.complete()
}
}
joinAll(job1!!, job2!!) // suspends until both jobs are done
job1 = null
job2 = null
// Do something one time
}