Day87 of #100DaysOfCode

Kushagra Kesav
4 min readMay 4, 2022

--

Day87 of #100DaysOfCode

Hii folks 🙌

Today I will be starting a new unit and pathway in which we will learn challenges with Multithreading in Android.

Unit 4: Internet

Pathway 1: Coroutines

https://developer.android.com/courses/android-basics-kotlin/course

Challenges with threads

Using threads is a simple way to start working with multiple tasks and concurrency, but is not problem-free. A number of problems can arise when we use Thread directly in our code.

Threads require a lot of resources

Creating, switching, and managing threads takes up system resources and time limiting the raw number of threads that can be managed at the same time. The costs of creation can really add up.

While a running app will have multiple threads, each app will have one dedicated thread, specifically responsible for our app’s UI. This thread is often called the main thread or UI thread.

Note: In some cases, the UI thread and main thread may be different.

Because this thread is responsible for running our app’s UI, it’s important for the main thread to be performant so that the app will run smoothly. Any long-running tasks will block it until completion and cause our app to be unresponsive.

The operating system does a lot to attempt to keep things responsive for the user. Current phones attempt to update the UI 60 to 120 times per second (60 at minimum). There’s a short finite time to prepare and draw the UI (at 60 frames per second, every screen update should take 16ms or less). Android will drop frames, or abort trying to complete a single update cycle to attempt to catch up. Some frames drop and fluctuation is normal but too many will make our app unresponsive.

Race conditions and unpredictable behavior

As discussed, a thread is an abstraction for how a processor appears to handle multiple tasks at once. As the processor switches between sets of instructions on different threads, the exact time a thread is executed and when a thread is paused are beyond our control. You can’t always expect predictable output when working with threads directly.

For example, the following code uses a simple loop to count from 1 to 50, but in this case, a new thread is created for each time the count is incremented. Think about what we’d expect the output to look like and then run the code a few times.

fun main() {
var count = 0
for (i in 1..50) {
Thread {
count += 1
println("Thread: $i count: $count")
}.start()
}
}

Was the output what we expected? Was it the same every time? Here’s an example output we got.

Thread: 50 count: 49 Thread: 43 count: 50 Thread: 1 count: 1
Thread: 2 count: 2
Thread: 3 count: 3
Thread: 4 count: 4
Thread: 5 count: 5
Thread: 6 count: 6
Thread: 7 count: 7
Thread: 8 count: 8
Thread: 9 count: 9
Thread: 10 count: 10
Thread: 11 count: 11
Thread: 12 count: 12
Thread: 13 count: 13
Thread: 14 count: 14
Thread: 15 count: 15
Thread: 16 count: 16
Thread: 17 count: 17
Thread: 18 count: 18
Thread: 19 count: 19
Thread: 20 count: 20
Thread: 21 count: 21
Thread: 23 count: 22
Thread: 22 count: 23
Thread: 24 count: 24
Thread: 25 count: 25
Thread: 26 count: 26
Thread: 27 count: 27
Thread: 30 count: 28
Thread: 28 count: 29
Thread: 29 count: 41
Thread: 40 count: 41
Thread: 39 count: 41
Thread: 41 count: 41
Thread: 38 count: 41
Thread: 37 count: 41
Thread: 35 count: 41
Thread: 33 count: 41
Thread: 36 count: 41
Thread: 34 count: 41
Thread: 31 count: 41
Thread: 32 count: 41
Thread: 44 count: 42
Thread: 46 count: 43
Thread: 45 count: 44
Thread: 47 count: 45
Thread: 48 count: 46
Thread: 42 count: 47
Thread: 49 count: 48

Contrary to what the code says, it looks like the last thread was executed first, and that some of the other threads were executed out of order. If we look at the “count” for some of the iterations, we’ll notice that it remains unchanged after multiple threads. Even odder, the count reaches 50 at Thread 43 even though the output suggests this is only the second thread to execute. Judging from the output alone, it’s impossible to know what the final value of count is.

These are just one-way threads that can lead to unpredictable behavior. When working with multiple threads, we may also run into what’s called a race condition. This is when multiple threads try to access the same value in memory at the same time. Race conditions can result in hard to reproduce, random-looking bugs, which may cause our app to crash, often unpredictably.

Performance issues, race conditions, and hard to reproduce bugs are some of the reasons why we don’t recommend working with threads directly. Instead, we’ll learn about a feature in Kotlin called Coroutines that will help us write concurrent code.

That is all for Day87 ✅

Thanks for reading, See you tomorrow!

--

--

Kushagra Kesav
Kushagra Kesav

Written by Kushagra Kesav

Developer Relations | Communities | Software Engineering | https://www.linkedin.com/in/kushagrakesav

No responses yet