在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
)
}
}
我知道(lock as java.lang.Object).wait()
丑陋,我最好选择ReentrantLock,但我有意将其降至最原始的水平。
现在,如果我在没有从Android主线程执行协程的情况下执行此函数,它将阻塞调用线程(预期行为):
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
someObject.doSomething()
}
但是,如果我只将它包装在也可以在主线程上执行的协程中,则主线程不再受阻,但是功能保持不变:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
CoroutineScope(Dispatchers.Main).launch {
val result = someObject.doSomething()
}
}
两个问题:
(lock as java.lang.Object).wait()
应该阻塞了主线程。当涉及协程时,怎么会没有呢?协程是否具有“拦截”这种低水平相互作用的方式?谢谢
答案 0 :(得分:7)
像post()
上的View
一样,launch()
(通常)安排要相对于当前执行位异步执行的工作。因此,传递给launch()
的lambda表达式中的代码最终将在主应用程序线程上运行,就像您提供给Runnable
的{{1}}将在主应用程序线程上运行一样最终。但是,您的post()
函数将继续超过onCreate()
的作用,以执行应做的其他事情。
但是,就像launch()
中传递的内容一样,传递给Runnable
的{{1}}仍然可以占用主应用程序线程,您的协程仍然可以占用主应用程序线。只是这项工作比直接在post()
中进行工作要晚。
只是动画仍然有效
IIRC,在更新版本的Android上,动画本身在单独的“渲染”线程上进行处理。