Home > Mobile >  Second coroutine is never executed
Second coroutine is never executed

Time:08-19

I have two coroutines inside another one, it's supposed that both inner coroutines are going to execute asynchronously, but this doesn't happened. The second one waits until the first finish. This is my code:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
     var flag = false
     override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_main)

          runBlocking {
                launch {
                    printOne()
                }
                launch {
                    printTwo()
                }
          }
    }

    suspend fun printOne() {
         while (flag == false)
             Log.e("log", "111111")
    }

    suspend fun printTwo() {
         Log.e("log", "222222")
         Log.e("log", "222222")
         Log.e("log", "222222")
         Log.e("log", "222222")
         flag = true
   }
}

I assumed that the code inside the first launch{} would execute in a thread separately from the code in the second launch{} as well as any other corutine. But it keeps looping for ever inside the first launch{}

CodePudding user response:

Is Log.e a suspend function? If not, then your first coroutine never calls another suspend function, and never explicitly yields, so it never gives other coroutines a chance to run on the same thread.

The call to runBlocking is using a default dispatcher that uses only one thread, so there's no thread available to run the second coroutine.

You could fix this by explicitly yielding after every loop iteration:

suspend fun printOne() {
    while (flag == false) {
        Log.e("log", "111111")
        yield() // <-- give other coroutines a turn
    }
}

If you try to fix the problem by using a different dispatcher (like runBlocking(Dispatchers.IO)), you may notice another problem...

The flag variable is not volatile. Changes to the variable made by a coroutine running in one thread might not be seen by cooroutines in a different thread for a long time, if ever. You could fix this by annotating the property as volatile:

@Volatile
var flag = false

CodePudding user response:

Coroutines are not threads. You can set them to run in different threads if you want, using Dispatchers, but if not, you have to let execution time for other coroutines in the same thread with yield() or delay(Long).

CodePudding user response:

You are using runBlocking. Replace it for lifecycleScope.launch.

The Android library for activities/fragment added a coroutine launcher tied to the lifecycle.

  • Related