我具有以下代码结构:
@Throws(InterruptedException::class)
fun method() {
// do some blocking operations like Thread.sleep(...)
}
var job = launch {
method()
}
job.cancelAndJoin()
method
由外部库提供,我无法控制其行为。执行可能会花费很多时间,因此在某些情况下,应通过超时将其取消。
我可以使用kotlin协程库提供的withTimeout
函数,但是由于协程的设计,它无法取消带有阻塞的代码。有解决方法吗?
答案 0 :(得分:4)
主要思想是将out of coroutines上下文线程池与可以以旧样式中断的自然线程一起使用,并订阅coroutines执行中的取消事件。当invokeOnCancellation
捕获到事件后,我们可以中断当前线程。
实现:
val externalThreadPool = Executors.newCachedThreadPool()
suspend fun <T> withTimeoutOrInterrupt(timeMillis: Long, block: () -> T) {
withTimeout(timeMillis) {
suspendCancellableCoroutine<Unit> { cont ->
val future = externalThreadPool.submit {
try {
block()
cont.resumeWith(Result.success(Unit))
} catch (e: InterruptedException) {
cont.resumeWithException(CancellationException())
} catch (e: Throwable) {
cont.resumeWithException(e);
}
}
cont.invokeOnCancellation {
future.cancel(true)
}
}
}
}
它提供了与通常的withTimeout
类似的行为,但是它还支持运行带有阻塞的代码。
注意:仅当您知道内部代码使用阻塞并且可以正确处理抛出的InterruptedException
时,才应调用它。在大多数情况下,首选withTimeout
函数。