【问题标题】:Kotlin Coroutines validate running on same DispatcherKotlin Coroutines 验证在同一个 Dispatcher 上运行
【发布时间】:2020-09-08 10:10:00
【问题描述】:

我有一个自定义 Scope,它使用单个线程作为 Dispatcher。

private val jsDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
private val jsScope = CoroutineScope(jsDispatcher + SupervisorJob() + CoroutineName("JS-Thread"))

假设我有一个代码块,它使用上述范围来启动一个新的协程并调用多个挂起方法

jsScope.launch {
    sampleMethod()
    sampleMethod2()
    sampleMethod3()
}

如果上面的示例方法之一没有在上面的 JS 线程上运行,我需要验证并抛出异常

private suspend fun sampleMethod() = coroutineScope {
    //Implement me
    validateThread()
}

如何执行?

【问题讨论】:

  • withContext(jsDispatcher)?
  • @Nicolas 不,这不是我想要的,如果我切换上下文,则无需验证 :)
  • 您可以使用Thread.currentThread().name 来检查当前线程名称,但是它的名称会像pool-2-thread-1 这样几乎无法验证。有一种方法可以自定义名称,但首先,我是否正确理解您的问题?为什么不withContext,如果线程错了你想怎么办?
  • @Nicolas 我已编辑问题以添加更多说明。一旦我使用方法 sampleMethod,我就不想切换上下文,因为我已经在上面了。但只是想验证没有其他人会来自另一个范围

标签: kotlin-coroutines


【解决方案1】:

您可以在您的方法中检查当前线程名称:

private suspend fun sampleMethod() = coroutineScope {
    assert(Thread.currentThread().name == "js-thread")  // Doesn't work!
}

但是,newSingleThreadExecutor 使用 DefaultThreadFactory 生成像 pool-N-thread-M 这样的线程名称,因为您不知道 M 或 N,所以无法真正验证。我在这里看到两种解决方案:

  1. 利用您只有一个线程这一事实,并在创建执行程序后立即更改其名称:

    runBlocking {
        jsScope.launch {
            Thread.currentThread().name = "js-thread"
        }
    }
    
  2. 传递自定义线程工厂:Executors.newSingleThreadExecutor(MyThreadFactory("js-thread"))

    private class MyThreadFactory(private val name: String) : ThreadFactory {
    
        private val group: ThreadGroup
        private val threadNumber = AtomicInteger(1)
    
        init {
            val s = System.getSecurityManager()
            group = if (s != null) {
                s.threadGroup
            } else {
                Thread.currentThread().threadGroup
            }
        }
    
        override fun newThread(r: Runnable): Thread {
            val t = Thread(group, r, "$name-${threadNumber.getAndIncrement()}", 0)
            if (t.isDaemon) {
                t.isDaemon = false
            }
            if (t.priority != Thread.NORM_PRIORITY) {
                t.priority = Thread.NORM_PRIORITY
            }
            return t
        }
    }
    

    代码改编自DefaultThreadFactory。 Guava 和 apache-commons 也提供了实用方法来做同样的事情。这样做的好处是它适用于任何线程池,而不仅仅是单线程。

【讨论】:

    【解决方案2】:

    经过一番研究,我查看了withContext() 的实现,我的问题的答案就在那里。

    取自 withContext() 实现,这是如何检查当前协程上下文是否与其他上下文/作用域位于同一调度程序上

    if (newContext[ContinuationInterceptor] === oldContext[ContinuationInterceptor]) {
        // same dispatcher
    }
    

    【讨论】:

      猜你喜欢
      • 2019-11-28
      • 2019-10-22
      • 2018-12-29
      • 2020-07-10
      • 2021-07-05
      • 2019-01-17
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      相关资源
      最近更新 更多