Я столкнулся с неожиданным поведением при использовании сопрограмм в приложении для 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()
должен был заблокировать основной поток. Как получается, когда сопрограмма задействована? У сопрограмм есть способ «перехватывать» такие низкоуровневые взаимодействия?
Спасибо