如何使用suspendCoroutine将java 7将来转换为kotlin挂起函数

loading...


4

在kotlin暂停函数中包装java 7期货的最佳方法是什么?有没有办法将返回Java 7期货的方法转换为挂起函数?

对于任意回调或java 8 completablefutures,该过程非常简单,如下所示:* https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#suspending-functions

在这些情况下,有一个钩子在未来完成时被触发,因此一旦未来的值准备好(或触发异常),它就可以用来恢复延续 .

但是,Java 7期货不公开计算结束时调用的方法 .

将Java 7未来转换为Java 8可完成的未来不是我的代码库中的一个选项 .

当然,我可以创建一个调用future.get()的挂起函数,但这会阻塞,这打破了使用协程暂停的总体目的 .

另一种选择是将runnable提交给新的线程 Actuator ,并在runnable调用future.get()内部并调用回调 . 从消费者的角度来看,这个包装器会使代码看起来像“非阻塞”,协程可以暂停,但是我们仍在编写阻塞代码,我们正在创建一个新的线程,只是为了阻止它

2回答

  • 3

    Java 7的未来正在受阻 . 它不是为异步API设计的,也没有提供任何方法来安装将来完成时调用的回调 . 这意味着没有直接使用 suspendCoroutine 的方法,因为 suspendCoroutine 设计用于使用异步回调的API .

    但是,如果您的代码实际上是在JDK 8或更新版本下运行,那么您的代码中实际的 Future 实例很可能会在运行时实现 CompletionStage 接口 . 您可以尝试将其强制转换为 CompletionStage ,并使用 kotlinx.coroutines 库的 kotlinx-coroutines-jdk8 模块中的即用型CompletionStage.await扩展名 .


  • 0

    当然Roman是正确的,Java Future 不允许您在工作完成时提供回调 .

    但是,它确实为您提供了检查工作是否完成的方法,如果是,则调用 .get() 将不会阻止 .

    幸运的是,对于我们来说,我们还有一种廉价的方法来转移线程,以便通过协同程序快速进行民意调查 .

    让我们编写轮询逻辑并将其作为扩展方法出售:

    suspend fun <T> Future<T>.wait(): T {
        while(!isDone)
            delay(1) // or whatever you want your polling frequency to be
        return get()
    }
    

    然后使用:

    fun someBlockingWork(): Future<String> { ... }
    
    suspend fun useWork() {
        val result = someBlockingWork().wait()
        println("Result: $result")
    }
    

    因此,我们对Futures完成的毫秒响应时间没有使用任何额外的线程 .


    当然,你会想要添加一些上限用作超时,这样你就不会永远等待 . 在这种情况下,我们可以稍微更新一下代码:

    suspend fun <T> Future<T>.wait(timeoutMs: Int = 60000): T? {
        val start = System.currentTimeMillis()
        while (!isDone) {
            if (System.currentTimeMillis() - start > timeoutMs)
                return null
            delay(1)
        }
        return get()
    }
    

loading...

评论

暂时没有评论!