当前位置: 首页 > 知识库问答 >
问题:

为什么以及如何Kotlin coroutine防止线程阻塞,即使没有“suspend”关键字?

程淮晨
2023-03-14

我在Android应用程序中使用coroutines时遇到了一些意想不到的行为。

假设我得到了下面的函数,它不是“suspend”。它启动辅助线程,并应该阻止调用线程,直到所有辅助线程终止:

fun doSomething() : Result {

    // producers init thread
    Thread {
        for (i in 0 until NUM_OF_MESSAGES) {
            startNewProducer(i) // each producer is a thread
        }
    }.start()

    // consumers init thread
    Thread {
        for (i in 0 until NUM_OF_MESSAGES) {
            startNewConsumer() // each consumer is a thread
        }
    }.start()


    synchronized(lock) {
        while (numOfFinishedConsumers < NUM_OF_MESSAGES) {
            try {
                (lock as java.lang.Object).wait()
            } catch (e: InterruptedException) {
                return@synchronized
            }
        }
    }

    synchronized(lock) {
        return Result(
                System.currentTimeMillis() - startTimestamp,
                numOfReceivedMessages
        )
    }

}

我知道(lock as java.lang.object).wait()很难看,使用ReentrantLock会更好,但我有意想降低到最原始的级别。

现在,如果我在没有来自Android主线程的coroutine的情况下执行此函数,它将阻塞调用线程(预期行为):

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    someObject.doSomething()
}

但是,如果我只是将它包装在一个也在主线程上执行的coroutine中,主线程不再被阻塞,但功能仍然相同:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    CoroutineScope(Dispatchers.Main).launch {
        val result = someObject.doSomething()
    }
}

两个问题:

  1. 我认为为了使coroutines工作,函数应该是“suspend”,但这里不是这样。那么,“suspend”有什么意义呢?
  2. 调用(锁为java.lang.object).wait()应该阻塞了主线程。为什么当coroutine参与的时候不会呢?coroutines有“拦截”这种低级交互的手段吗?

谢谢

共有1个答案

柯易安
2023-03-14

视图上的post()类似,launce()(通常)调度要针对当前执行位异步执行的工作。因此,传递给launn()的lambda表达式中的代码最终将在主应用程序线程上运行,就像您提供给post()runnable最终将在主应用程序线程上运行一样。但是,oncreate()函数将继续超过launce()点,以执行它应该执行的任何其他操作。

但是,就像传递给post()runnable仍然会因为它在run()中所做的工作而绑定主应用程序线程一样,您的coroutine仍然会绑定主应用程序线程。只是这项工作会比直接在oncreate()中完成这项工作要晚。

只是动画还能用

IIRC,在新版本的Android上,动画本身在一个单独的“渲染”线程上处理。

 类似资料:
  • 线程实例的join()方法可用于将一个线程的执行开始“连接”到另一个线程的执行结束,这样一个线程在另一个线程结束之前不会开始运行。如果对线程实例调用join(),则当前运行的线程将阻塞,直到线程实例完成执行 但是如果我有多个线程并且当我在循环内部调用join时。所有线程并行运行。但是根据连接的概念,首先连接的线程应该完成,然后只有主线程才允许连接其他线程。 } 在上面的代码中,如果第一个线程被连接

  • 我不明白为什么webclient会阻止我使用gradle的主要netty线程,以下是它的依赖项: 这个gradle脚本在两个应用程序中都使用。在第一个应用程序中,我执行: 第二个应用程序模拟长响应处理: 我希望呼叫服务不会阻塞主线程,而是会继续处理传入的连接,但直到我收到第一个呼叫的响应(睡眠将起作用),我的下一个连接将挂起等待。 结果:第一个应用程序像tomcat一样工作,只有一个线程 我的问题

  • 问题内容: 当用户选择在另一个线程中启动阻止进程的菜单项时,我试图在JavaFX 8应用程序中提供反馈。在我的实际应用程序中,它是文件下载,但是通过示例,我使用最少的代码创建了一个测试用例: 它的工作方式如下:当选择“开始”菜单项时,主菜单文本应立即更改为“正在运行…”,然后应附加“完成!”。经过5秒钟的模拟我的文件下载的睡眠。 实际上发生的是,即使我正在使用,在阻止过程完成 后 , 两个 文本更

  • 在服务器端,内存消耗正常,线程量约为250个,看起来一切正常。我没有看到任何问题,所以我决定解决服务器端标记为严重的所有问题。 我遇到的第一个是: 检测到阻塞的系统关键线程。这可能导致群集范围内的未定义行为[threadname=tcp-comm-worker,blockedfor=13s] https://yadi.sk/d/mme0xrgi3k6lka 补充:这个问题似乎不是无关紧要的,这个消

  • 我想知道Java中是否有某种方法可以立即停止线程。我不想检查它的中断状态,我需要立即停止它。这是因为在Thread的run方法中有许多计算,为了使用interrupted实现我想要的结果,我必须到处注入状态检查。那么有什么方法可以立即中断线程吗?也许stop()方法?我知道有人说它不应该被使用,因为死锁,但如果它可以解决我的问题(即使它会引起另一个问题;))我可以用它。所以?附注。我知道有其他类似

  • 我使用 C 和 POSIX 线程创建了一个多线程应用程序。我现在应该阻塞一个线程(主线程),直到设置了布尔标志(变为真)。 我找到了两种方法来完成这件事。 > 在没有睡眠的情况下旋转。 在睡眠中旋转循环。 如果我应该遵循第一种方式,为什么有些人编写代码遵循第二种方式?如果应该使用第二种方法,为什么要让当前线程Hibernate呢?这种方式的缺点是什么?