Non-blocking concurrent code

Threads and Kotlin Coroutines

André Rodrigues
3 min readOct 21, 2021

Threads

The concept of a Thread is a little abstract but we understand as some path of code that are executed in sequence (synchronously). In any application we have at least one Thread running, in case of a Mobile application the Main Thread is usually the UI Thread.

When an app is running we can have some threads executing different parts of code, that is called multitasking. Behind the scenes the processor does not run the threads simultaneously for real but switching between them given the appearance of a parallel execution.

One common problem in an app that we can resolve using Threads is, imagine a scroll view list that loads different images from internet, if you scroll to the bottom of the list before the app loads the next items the app stops the scroll until load more data. To resolve that kind of issues in the UI we can use threads, in that particular way using another thread just to request and load new items in parallel when the list still scrolling down.

Although, handle Threads directly may cause some problems:

  • Performance issues
    Manage threads implies to spent a lot of from system resources like battery and time
  • Race conditions
    Threads can be started and stopped only based in your time of execution. When different Threads are sharing the same variable we can not guarantee that a thread has already finished your operation with that variable before the next Thread requires the same variable

Code example

import kotlin.random.Randomfun main(args: Array<String>) {
var total = 100
val states = arrayOf("Starting", "Doing Task 1", "Doing Task 2", "Ending")
val values = arrayOf(-50, 60, 10, -20)
Random.nextInt(3).let {
println("Current state: ${states.get(it)}")
}
repeat(4) {
Thread {
println("Thread: $it total: $total")
total += values.get(it)
Thread.sleep(1000L)
}.start()
}
}

Coroutines

Coroutines Is similar to Threads, it allows us to run code in parallel, but more safe than manage Threads.

All coroutines run inside a scope, handled by its job. When we cancel the job, it cancels all routines on that scope
A dispatcher controls which Thread will run the coroutine. In Kotlin we have three types: the Main is responsible by UI tasks, the IO ideally to handle Networking and database operations, and Default is indicated to CPU intensive tasks.

Code example

import kotlinx.coroutines.*
import kotlin.random.Random
fun main(args: Array<String>) {
var total = 100
val states = arrayOf("Starting", "Doing Task 1", "Doing Task 2", "Ending")
val values = arrayOf(-50, 60, 10, -20)
runBlocking {
Random.nextInt(3).let {
println("Current state: ${states.get(it)}")
}
repeat(4) {
launch {
println("Thread: $it total: $total")
total += values.get(it)
delay(1000L)
}
}
}
}

Other benefit that we can achieve with Coroutines is substitute of callback pattern. Callback pattern is a way to create an asynchronous flow code, but it comes with some issues like “Callback Hell”, when we have so many callbacks chained together that it turns the code too complicated to read, understand and maintain. Other con is that to handle errors we may we will need write too much code. So to avoid those a good alternative is Coroutines, that allow us to write asynchronous code in a sequential way.

--

--

André Rodrigues
André Rodrigues

Written by André Rodrigues

Latin American • Brazil • São Paulo

No responses yet