1. What is the difference between the job returned by launch and the CoroutineContext[job] passed in?
  2. What’s the difference between a coroutineScope and a coroutineScope?

Lunch {} returns Job. Scope. Async {} returns Deferred(inherited from Job).

Val job () = job (); val job () = job (); The Job() method returns a JobImpl object, which ultimately implements the Job interface.

The Job() method passes in a nullable parentJob as the parent of the one you want to generate, and parentjob.cancel () causes all child jobs under the parent to cancel.

We also need to know that the first parameter that scope.launch() can be passed in is CoroutineContext, which has a number of subclasses. The Job we’re usually used to, the Job(Job, container Job), CoroutineDispatcher (Dispatcher. The Main and so on), CoroutineExceptionHandler (to catch exceptions), CoroutineName (often used for debugging) and so on, and CoroutineContext overloaded + shipping IO, or job+ dispatcher. Main + myExceptionHandler, etc., to represent a coroutineContext, CoroutineContext [Job] is a CoroutineContext Job, and so on.

Problem a

@Test
​fun getData() = runBlocking {
    val job1 = Job()
    val job2 = GlobalScope.launch(job1){
        delay(2000L)
        println("hello")
    }
    //  job1.cancel()
    job2.cancel()
    job2.join()
}
Copy the code

Job1, job2 can cancel the coroutine we started, which means “hello” can’t be printed.

Let’s take a look at the following situation

@Test
fun getData() = runBlocking {
    val job1 = Job()
    val job2 = GlobalScope.launch(job1){
        delay(2000L)
        println("hello")
    }

    val job3 = GlobalScope.launch (job1){
        delay(3000L)
        println("world")
    }
    //  job1.cancel()
    job2.cancel()
    joinAll(job2,job3)
}
Copy the code

When we call job1.cancel(), we see no output. When we call job2.cancel(), we see only “world” output. In other words, job1.cancel() cancels both coroutines. Job2.cancel () simply cancels the first coroutine. In other words, Job1 is more like the parent job of JoB2 and Job3 and can manage the life cycle of coroutines in scope.

If JOb2 throws an exception and I cancel none of the jobs, world will print.

 @Test
    fun getData() = runBlocking {
        val job1 = Job()
        val job2 = GlobalScope.launch(job1) {
            delay(2000L)
            throw NullPointerException()
        }

        val job3 = GlobalScope.launch(job1) {
            delay(3000L)
            println("world")
        }
//        job1.cancel()
//        job2.cancel()
        joinAll(job2, job3)
    }
Copy the code

The answer is no, why not? We’ll discuss this in a future article. So what if I want to print, that is, my joB2 control coroutine throw exception does not affect my job3 control coroutine execution? It’s simple, the joB1 is changed to val JoB1 =SupervisorJob(), we’ll discuss why.

But there’s a catch here

What is the output of the following code?

@Test
fun getData() = runBlocking {
    val job = Job()
    val job1 = GlobalScope.launch(job) {
        delay(2000L)
        throw  CancellationException()
        println("hello")
    }

    val job2 = GlobalScope.launch(job) {
        delay(3000L)
        println("world")
    }
    joinAll(job1,job2)
}
Copy the code

CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException CancellationException It doesn’t affect the parent coroutine and the sibling coroutine.

Question 2

The first thing we need to check is, what is a coroutineScope{}? It’s actually a suspend method that suspends the coroutine on a thread. In other words, suspend blocks the current coroutine, suspending it temporarily, but it doesn’t block the thread. If the suspend method doesn’t execute on the thread on which the coroutine is running, the thread will do something else until the suspend method ends. Then the coroutine starts to schedule, and then it continues to execute the code that started after the suspend method.

CoroutineScope we all know, CoroutineScope, common like lifecycleScope, viewModelScope. Let’s look at what the coroutineScope() method does.

@Test
fun getData() = runBlocking {
    val job = GlobalScope.launch {
        coroutineScope {
            val job1 = launch {
                delay(3000L)
                println("job1")
            }

            val job2 = launch {
                delay(2000L)
                println("job2")
            }
        }
        val job3 = launch {
            println("job3")
        }
    }
    job.join()
}
Copy the code

The result of this code is obvious: joB2 joB1 job3

The couroutineScope() method feels like a coroutine scoped builder, meaning that the code in that builder blocks the coroutine executed by the couroutineScope() method, meaning that the code in my builder has to make sure that it completes before your coroutine can proceed. The difference between the coroutineScope() method and the supervisorScope() method, however, is that it is similar to the Job() and the Job() method in that it is designed to be seen whether the coroutine throw anomalies are interacting with each other.

Here is a preview of the corresponding problem in coroutine two

3. How is the coroutine context propagated between parent coroutines?

4. How do coroutines propagate between parent coroutines and sibling coroutines?

Coroutine is a very big knowledge, the author will learn while sharing, encountered wrong place also hope you don’t hesitate to give advice.