1. Blocking and non blocking
runBlocking
delay is non blocking, thread Sleep is blocked. Explicitly use the runBlocking coroutine builder to block.
import kotlinx.coroutines.* fun main() { GlobalScope.launch { // Start a new collaboration in the background and continue delay(200) "rustfisher.com".forEach { print(it) delay(280) } } println("The code in the main thread executes immediately") runBlocking { // This expression blocks the main thread delay(3000L) //Blocking the main thread to prevent too fast exit } println("\n End of example") }
As you can see, runBlocking uses delay to delay. The main process using runBlocking will be blocked until the execution of the internal co process of runBlocking is completed. That is, runBlocking {delay} realizes the blocking effect.
We can also wrap the main function with runBlocking.
import kotlinx.coroutines.* fun main() = runBlocking { delay(100) // You can use delay here GlobalScope.launch { delay(100) println("Fisher") } print("Rust ") delay(3000) }
< unit > in runblocking < unit > can be omitted at present.
runBlocking can also be used in testing
// Introduce junit dependencies { implementation("junit:junit:4.13.1") }
unit testing
Set up a Test using @ Test
import org.junit.Test import kotlinx.coroutines.* class C3Test { @Test fun test1() = runBlocking { println("junit Test start ${System.currentTimeMillis()}") delay(1234) println("junit End of test ${System.currentTimeMillis()}") } }
Operation results
junit Test start 1632401800686 junit End of test 1632401801928
IDEA may prompt no tasks available. You need to change the test option to IDEA, as shown in the following figure.
change setting
2. Wait
Sometimes it is necessary to wait for the execution of the cooperation process. You can use the join() method. This method will suspend the current process until the execution is completed. You need to use main() = runBlocking.
import kotlinx.coroutines.* fun main() = runBlocking { println("Test wait") val job1 = GlobalScope.launch { println("job1 start") delay(300) println("job1 done") } val job2 = GlobalScope.launch { println("job2 start") delay(800) println("job2 done") } job2.join() job1.join() // wait for println("End of test") }
Run log
Test wait job1 start job2 start job1 done job2 done End of test
3. Structured concurrency
Use globalscope When launching, a top-level collaboration will be created. It does not use the main thread. Although the newly created collaborative process is lightweight, it will still consume some memory resources. If you forget to keep the reference to the newly started collaboration, it will continue to run.
We can use structured concurrency in our code.
In the example, we use the runBlocking coroutine builder to convert the main function into a coroutine. There is no need to explicitly use join for the coprocessor started in the scope.
Observe the following example:
import kotlinx.coroutines.* fun main() = runBlocking<Unit> { println("Main thread id ${Thread.currentThread().id}") launch { // Start a new procedure 1 in the runBlocking scope println("Thread of coroutine 1 id ${Thread.currentThread().id}") delay(300) println("Collaboration 1 completed") } launch { // Start a new process 2 in the runBlocking scope println("Thread of coroutine 2 id ${Thread.currentThread().id}") delay(500) println("Collaboration 2 completed") } println("Main thread execution completed") }
Run log
Main thread id 1 Main thread execution completed Thread of coroutine 1 id 1 Thread of coroutine 2 id 1 Collaboration 1 completed Collaboration 2 completed
As you can see, you don't need to call thread as before Sleep or delay makes the main thread wait for a period of time to prevent the virtual machine from exiting.
The program will wait until all its co processes are executed, and then really exit.
4. Scope builder
Declare your own scope using the coroutine scope builder. It creates a collaboration scope and waits for all started child collaborations to be executed.
runBlocking looks similar to coroutineScope because they both wait for the body of their coroutines and all their child coroutines to end. The main differences are:
- The runBlocking method blocks the current thread to wait. It is a normal function
- coroutineScope is only suspended. It will release the underlying thread for other purposes. It is a suspended function
The following example shows the characteristics of the scope builder. main is a scope.
import kotlinx.coroutines.* fun main() = runBlocking { // this: CoroutineScope launch { delay(200L) println("Synergetic process 1 t${Thread.currentThread().id}") } coroutineScope { // Create a collaboration scope launch { delay(500L) println("Internal coordination process 2-1 t${Thread.currentThread().id}") } delay(100L) println("Synergetic process 2 t${Thread.currentThread().id}") } println("Main task completed") }
Run log
Synergetic process 2 t1 Synergetic process 1 t1 Internal coordination process 2-1t1 Main task completed
5. Extract function reconstruction
Extract the code block inside launch {...} into a separate function. The extracted function needs the suspend modifier, which is a suspended function.
import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking fun main() = runBlocking<Unit> { launch { r1() } println("DONE") } // Suspend function suspend fun r1() { delay(300) println("Extracted function") }
log
DONE Extracted function
6. The coordination process is light
We have also tried to create a lot of collaborative processes before, and the program runs OK.
The following code can output many points
import kotlinx.coroutines.* fun main() = runBlocking { for (t in 1..10000) { launch { delay(t * 500L) print(".") } } }
7. The global process is like a daemon thread
If only the daemon thread is left in the process, the virtual opportunity exits. In the previous example, you can also see that the program ends before the characters are printed.
The active orchestration started in GlobalScope does not keep the process alive. They are like daemon threads.
Another example
import kotlinx.coroutines.* fun main() = runBlocking { GlobalScope.launch { for (i in 1..1000000) { delay(200) println("Collaborative execution: $i") } } delay(1000) println("Bye~") }
log
Collaborative execution: 1 Collaborative execution: 2 Collaborative execution: 3 Collaborative execution: 4 Bye~
kotlin data sharing
Advanced Kotlin enhanced combat