为什么和如何Kotlin协程防止线程阻塞,即使没有“ suspend”关键字也是如此?

Vas*_*liy 3 multithreading android kotlin kotlin-coroutines

在Android应用中使用协程时遇到了一些意外行为。

假设我有以下功能,它不是“挂起”。它启动工作线程,并应阻塞调用线程,直到所有工作线程终止:

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
        )
    }

}
Run Code Online (Sandbox Code Playgroud)

我知道这(lock as java.lang.Object).wait()很丑陋,使用ReentrantLock会更好,但我有意将其降至最原始的水平。

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

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    someObject.doSomething()
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我仅将它包装在也可以在主线程上执行的协程中,则不再阻塞主线程,但是功能保持不变:

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

两个问题:

  1. 我认为,为了使协同程序正常工作,应将功能“挂起”,但实际情况并非如此。那么,“挂起”的意义何在?
  2. 呼叫(lock as java.lang.Object).wait()应该已经封锁了主线程。当涉及协程时,怎么会没有呢?协程是否具有“拦截”这种低水平相互作用的方式?

谢谢

Com*_*are 7

post()在上一样Viewlaunch()(通常)安排要相对于当前执行位异步执行的工作。因此,传递给您的lambda表达式中的代码launch()最终将在主应用程序线程上运行,就像Runnable您提供的最终post()将在主应用程序线程上运行一样。但是,您的onCreate()功能将继续进行,launch()以做其他应做的事情。

但是,就像Runnablepassed post()由于其所做的工作仍然可以占用主应用程序线程一样run(),您的协程仍可以占用主应用程序线程。只是这项工作比直接在中进行工作要晚onCreate()

只是动画仍然有效

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