简体   繁体   中英

Kotlin Coroutines - Thread Switching

I am new to Android Coroutines . I've been reading about it from the official docs and found this note

Important: Using a dispatcher that uses a thread pool like Dispatchers.IO or Dispatchers.Default does not guarantee that the block executes on the same thread from top to bottom. In some situations, Kotlin coroutines might move execution to another thread after a suspend-and-resume. This means thread-local variables might not point to the same value for the entire withContext() block.

but I didn't get this specific sentence

This means thread-local variables might not point to the same value for the entire withContext() block

Can anyone show me an example of this scenario?

myLooper() and prepare() on Looper use a thread-local variable for holding a per-thread Looper instance.

So, imagine this scenario:

  • You launch() a coroutine on Dispatchers.Default
  • In that coroutine, you prepare() a Looper and try using that for something (eg, with a Messenger )
  • You then call some suspend function

When that suspend function returns, you may not be on the same thread as you were on before calling that suspend function. It will be a thread from Dispatchers.Default , but not necessarily the specific thread you were on before. As a result, your Looper might be associated with some other thread, one that you're fighting with the coroutines system to use. Depending on what you were trying to do here, the fact that you are on a different thread might cause problems in what you wanted the Looper for.

The real lesson here is: use HandlerThread to get a Looper , rather than prepare() .

This refers to variables that are static to a thread (see this for reference).

Most likely this does not concern you, usage of thread local variables is rather specific. The fact that your coroutine may jump to a different thread when resumed will have no impact in normal cases.

What they try to express is that in a withContext(IO) {...} what happens is not. IO -> give me thread (A) -> execute {... } -> come back to me instead it is IO -> give me thread (A) -> start executing {... } ~> put the work away if you hit a suspend ~> come on do something thread (B) might also be thread (A) keeps on working -> some back with a result.

withContext(IO) { //starts executing on Thread A
     println(currentThread().name //runs on Thread A
     delay(100) //suspending put the work away
     println(currentThread().name //picks up again on Thread B or A or C whatever
   }

This is the same issue in any async code that runs on more than one thread. Certain libraries like rxjava allow to make work sticky.
Kotlin does take care of moving the local variables around in the context so for normal variables it is not a problem. But if you use something like logging utils which store certain context information in ThreadLocal then this will not work as expected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM