如何取消协程中的阻止代码

时间:2019-10-15 20:19:47

标签: android asynchronous kotlin kotlin-coroutines

我具有以下代码结构:

 @Throws(InterruptedException::class)
 fun method() {
     // do some blocking operations like Thread.sleep(...)
 }
 var job = launch {
     method()
 }
 job.cancelAndJoin()

method由外部库提供,我无法控制其行为。执行可能会花费很多时间,因此在某些情况下,应通过超时将其取消。

我可以使用kotlin协程库提供的withTimeout函数,但是由于协程的设计,它无法取消带有阻塞的代码。有解决方法吗?

1 个答案:

答案 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函数。