One: asynchrony of coroutines

task

private fun task(){
    println("currentThread:${Thread.currentThread().name}, time:${System.currentTimeMillis()}, start")
    Thread.sleep(1000)
    println("currentThread:${Thread.currentThread().name}, time:${System.currentTimeMillis()}, end")
}
Copy the code

Using coroutines asynchronously, let task() be processed in child threads.

Mode 1: Launch ()+ dispatchers.io

Launch create coroutine;

Dispatchers.IO scheduling, network time consuming in child threads

fun testNotSync() { println("currentThread:${Thread.currentThread().name}, time:${System.currentTimeMillis()}, Method start") // Repeat 3 times Repeat (3) {CoroutineScope(dispatchers.io).launch {task()}} Println ("currentThread:${thread.currentThread ().name}, time:${system.currentTimemillis ()}, end") Thread.sleep(10000)}Copy the code

Results:

CurrentThread :main, time:1631949431058 start currentThread:main, time:1631949431166 Method end currentThread: DefaultDispatcher - worker - 3 @ coroutine# 3, time: 1631949431176, start currentThread:DefaultDispatcher-worker-1 @coroutine#2, time:1631949431182, start currentThread:DefaultDispatcher-worker-2 @coroutine#1, time:1631949431182, start currentThread:DefaultDispatcher-worker-3 @coroutine#3, time:1631949432176, end currentThread:DefaultDispatcher-worker-1 @coroutine#2, time:1631949432182, end currentThread:DefaultDispatcher-worker-2 @coroutine#1, time:1631949432183, endCopy the code

Display: main thread content is executed first, then asynchronously executed in 3 child threads

Method 2: async()+ dispatchers.io

fun testByCoroutineAsync() { println("currentThread:${Thread.currentThread().name}, time:${System.currentTimeMillis()}, Method start") repeat(3){CoroutineScope(dispatchers.io).async {task()}} Println ("currentThread:${thread.currentThread ().name}, time:${system.currentTimemillis ()}, end") Thread.sleep(10000)}Copy the code

Results:

CurrentThread :main @coroutine#1, time:1631957324981 Method end currentThread: @ coroutine# DefaultDispatcher - worker - 1 3, time: 1631957325007, start currentThread:DefaultDispatcher-worker-2 @coroutine#2, time:1631957325007, start currentThread:DefaultDispatcher-worker-4 @coroutine#4, time:1631957325007, start currentThread:DefaultDispatcher-worker-1 @coroutine#3, time:1631957326007, end currentThread:DefaultDispatcher-worker-4 @coroutine#4, time:1631957326007, end currentThread:DefaultDispatcher-worker-2 @coroutine#2, time:1631957326007, endCopy the code

Display: main thread content is executed first, then asynchronously executed in 3 child threads

Async = coroutinescope.launch; async = coroutinescope.launch; async = coroutinescope.launch

Method 3: withContext+ dispatchers.io

*/ fun testByWithContext() = runBlocking { println("currentThread:${Thread.currentThread().name}, time:${System.currentTimeMillis()}, {task()} println("currentThread:${thread.currentThread ().name}, Time :${system.currentTimemillis ()}, end")Copy the code

Results:

CurrentThread: 1, the main @ coroutine# time: 1631958195591, method start currentThread: @ coroutine# DefaultDispatcher - worker - 1 1, time:1631958195669, start currentThread:DefaultDispatcher-worker-1 @coroutine#1, time:1631958196669, End currentThread:main @coroutine#1, time:1631958196671, endCopy the code

The withContext task is executed in the child thread, but it also blocks the main thread and finally executes “method end”.

Since withContext cuts the IO thread, it also suspends the external coroutine (understandable thread), and will not return to the original coroutine until the execution of withCotext is completed, which can also be interpreted as blocking the current thread.

So this is an asynchronous execution of a single withCotext, how about multiple withContexts?

fun testByWithContext() = runBlocking { println("currentThread:${Thread.currentThread().name}, Time :${system.currentTimemillis ()}, start") Repeat (3) {println("repeat it = $it") withContext(dispatchers.io) {task()}} Println ("currentThread:${thread.currentThread ().name}, time:${system.currentTimemillis ()}, end") Thread.sleep(10 *1000)} thread.sleep (10 *1000)}Copy the code

Results:

currentThread:main @coroutine#1, time:1631958027834, Methods start repeat it = 0 currentThread: @ coroutine# DefaultDispatcher - worker - 1 1, time: 1631958027870, start currentThread:DefaultDispatcher-worker-1 @coroutine#1, time:1631958028870, end repeat it = 1 currentThread:DefaultDispatcher-worker-1 @coroutine#1, time:1631958028873, start currentThread:DefaultDispatcher-worker-1 @coroutine#1, time:1631958029873, end repeat it = 2 currentThread:DefaultDispatcher-worker-1 @coroutine#1, time:1631958029874, start currentThread:DefaultDispatcher-worker-1 @coroutine#1, time:1631958030874, end currentThread:main @coroutine#1, End time: 1631958030874, methodCopy the code

Discovery: The main thread executes first, and then a withContext asynchronous execution completes before the next withContext asynchrony can be executed

Realized the synchronization of multiple asynchronous tasks, when we have multiple interface requests, need to be executed in order, can be used

Ii: Concurrency of coroutines (synchronization)

Concurrent processing in Java, the basic use of synchronized, Lock, join, etc. Now let’s see what coroutines do.

1: @synchronized annotation

Let’s update the task (@synchronized) and launch it asynchronously.

use

/** * @synchronized modify normal function ok, */ @synchronized private fun taskSynchronize(){println("currentThread:${thread.currentThread ().name}, time:${System.currentTimeMillis()}, start") Thread.sleep(1000) println("currentThread:${Thread.currentThread().name}, time:${System.currentTimeMillis()}, end") }Copy the code

Test: Aunch asynchronously accesses the taskSynchronize() task simultaneously

fun testCoroutineWithSync() { println("currentThread:${Thread.currentThread().name}, time:${System.currentTimeMillis()}, Start ") repeat(3){CoroutineScope(dispatchers.io).launch {taskSynchronize()}} Println ("currentThread:${thread.currentThread ().name}, time:${system.currentTimemillis ()}, end") Thread.sleep(10000)}Copy the code

Results:

Start currentThread:main, time:1631959341585, Method end currentThread: DefaultDispatcher - worker - 4 @ coroutine# 3, time: 1631959341657, start currentThread:DefaultDispatcher-worker-4 @coroutine#3, time:1631959342658, end currentThread:DefaultDispatcher-worker-1 @coroutine#1, time:1631959342658, start currentThread:DefaultDispatcher-worker-1 @coroutine#1, time:1631959343658, end currentThread:DefaultDispatcher-worker-2 @coroutine#2, time:1631959343658, start currentThread:DefaultDispatcher-worker-2 @coroutine#2, time:1631959344658, endCopy the code

Discovery: Main first completes execution, and then each thread task completes synchronization.

The problem

Not when the @synchronized annotated method has a suspend function and is blocking

Thread. Sleep (1000) is delay(1000).

Synchronize(); /** * synchronize (); /** * Synchronized () */ @synchronized suspend fun taskSynchronizeByDelay(){println("currentThread:${thread.currentThread ().name}, time:${System.currentTimeMillis()}, start") delay(1000) println("currentThread:${Thread.currentThread().name}, time:${System.currentTimeMillis()}, end") }Copy the code
/** * The execution body is taskSynchronizeByDelay(), which uses the delay function to suspend external threads while other threads can access the execution body. ** Therefore: @synchronized */ funTestCoroutineWithSync2 () {println("currentThread:${thread.currentThread ().name}, time:${System.currentTimeMillis()}, Start ") repeat(3){CoroutineScope(dispatchers.io).launch {taskSynchronizeByDelay()}} Println ("currentThread:${thread.currentThread ().name}, time:${system.currentTimemillis ()}, end") Thread.sleep(10000)}Copy the code

Results:

CurrentThread :main, time:1631961179390 Method end currentThread: @ coroutine# DefaultDispatcher - worker - 1 1, time: 1631961179456, start currentThread:DefaultDispatcher-worker-4 @coroutine#3, time:1631961179464, start currentThread:DefaultDispatcher-worker-3 @coroutine#2, time:1631961179464, start currentThread:DefaultDispatcher-worker-3 @coroutine#1, time:1631961180462, end currentThread:DefaultDispatcher-worker-3 @coroutine#3, time:1631961180464, end currentThread:DefaultDispatcher-worker-4 @coroutine#2, time:1631961180464, endCopy the code

Synchronized (@synchronized, asynchronous); delay suspends the external coroutine until it completes.

2: the Mutex ()

Use:

var mutex = Mutex()
mutex.withLock {
    // TODO
}
Copy the code

Testing:

fun testSyncByMutex() = runBlocking { var mutex = Mutex() println("currentThread:${Thread.currentThread().name}, time:${System.currentTimeMillis()}, Method start") repeat(3){CoroutineScope(dispatchers.io).launch {mutex.withlock {task()}} Println ("currentThread:${thread.currentThread ().name}, time:${system.currentTimemillis ()}, end") Thread.sleep(10000)}Copy the code

Results:

Start currentThread:main @coroutine#1, time:1631951230178, Method end currentThread: @ coroutine# DefaultDispatcher - worker - 1, 2 time: 1631951230178, start currentThread:DefaultDispatcher-worker-1 @coroutine#2, time:1631951231178, end currentThread:DefaultDispatcher-worker-2 @coroutine#3, time:1631951231183, start currentThread:DefaultDispatcher-worker-2 @coroutine#3, time:1631951232183, end currentThread:DefaultDispatcher-worker-1 @coroutine#4, time:1631951232183, start currentThread:DefaultDispatcher-worker-1 @coroutine#4, time:1631951233184, endCopy the code

Discovery: Multiple asynchronous tasks completed synchronously.

3: the Job. The join ()

Job Creates the handle returned by the coroutine, which supports join(). The class is the Join function of the Java thread, which can wait for the task to complete and implement synchronization

Testing:

fun testSyncByJob() = runBlocking{ println("currentThread:${Thread.currentThread().name}, time:${System.currentTimeMillis()}, Repeat (3){var job = CoroutineScope(dispatchers.io).launch {task()} job.start() job.join()} Println ("currentThread:${thread.currentThread ().name}, time:${system.currentTimemillis ()}, end") Thread.sleep(10000)}Copy the code

Results:

CurrentThread: 1, the main @ coroutine# time: 1631959997427, method start currentThread: @ coroutine# DefaultDispatcher - worker - 1, 2 time:1631959997507, start currentThread:DefaultDispatcher-worker-1 @coroutine#2, time:1631959998507, end currentThread:DefaultDispatcher-worker-1 @coroutine#3, time:1631959998509, start currentThread:DefaultDispatcher-worker-1 @coroutine#3, time:1631959999509, end currentThread:DefaultDispatcher-worker-1 @coroutine#4, time:1631959999510, start currentThread:DefaultDispatcher-worker-1 @coroutine#4, time:1631960000510, end currentThread:main @coroutine#1, End time: 1631960000510, methodCopy the code

Discovery: Multiple tasks can be completed synchronously and block the main thread, just like withContext.

4: already

Use:

val lock = ReentrantLock()
lock.lock()
task()
lock.unlock()
Copy the code

Testing:

fun testReentrantLock2() = runBlocking { val lock = ReentrantLock() println("currentThread:${Thread.currentThread().name}, time:${System.currentTimeMillis()}, Repeat (3){CoroutineScope(dispatchers.io).launch {lock.lock() task() lock.unlock()}} Println ("currentThread:${thread.currentThread ().name}, time:${system.currentTimemillis ()}, end") Thread.sleep(10000)}Copy the code

Results:

CurrentThread :main @coroutine#1, time:1631960884403 Method end currentThread: @ coroutine# DefaultDispatcher - worker - 1, 2 time: 1631960884445, start currentThread:DefaultDispatcher-worker-1 @coroutine#2, time:1631960885446, end currentThread:DefaultDispatcher-worker-5 @coroutine#4, time:1631960885446, start currentThread:DefaultDispatcher-worker-5 @coroutine#4, time:1631960886446, end currentThread:DefaultDispatcher-worker-2 @coroutine#3, time:1631960886446, start currentThread:DefaultDispatcher-worker-2 @coroutine#3, time:1631960887447, endCopy the code

Discovery: Synchronization is complete.