Reader small image

You're reading from  Kotlin Design Patterns and Best Practices - Second Edition

Product typeBook
Published inJan 2022
Reading LevelBeginner
PublisherPackt
ISBN-139781801815727
Edition2nd Edition
Languages
Right arrow
Author (1)
Alexey Soshin
Alexey Soshin
author image
Alexey Soshin

Alexey Soshin is a software architect with 15 years of experience in the industry. He started exploring Kotlin when Kotlin was still in beta, and since then has been a big enthusiast of the language. He's a conference speaker, published writer, and the author of a video course titled Pragmatic System Design.
Read more about Alexey Soshin

Right arrow

Chapter 6: Threads and Coroutines

In the previous chapter, we had a glance at how our application can efficiently serve thousands of requests per second—to discuss why immutability is important, we introduced a race condition problem using two threads.

In this chapter, we'll dive deeper into how to launch new threads in Kotlin and the reasons why coroutines can scale much better than threads. We will discuss how the Kotlin compiler treats coroutines and the relationship between coroutine scopes and dispatchers. We'll discuss the concept of structured concurrency, and how it helps us prevent resource leaks in our programs.

We'll cover the following topics in this chapter:

  • Looking deeper into threads
  • Introducing coroutines and suspend functions
  • Starting coroutines
  • Jobs
  • Coroutines under the hood
  • Dispatchers
  • Structured concurrency

After reading this chapter, you'll be familiar with Kotlin's concurrency primitives...

Technical requirements

In addition to the requirements from the previous chapters, you will also need a Gradle-enabled Kotlin project to be able to add the required dependencies.

You can find the source code for this chapter here: https://github.com/PacktPublishing/Kotlin-Design-Patterns-and-Best-Practices/tree/main/Chapter06.

Looking deeper into threads

Before we dive into the nuances, let's discuss what kinds of problems threads can solve.

In your laptop, you have a CPU with multiple cores – probably four of them, or even eight. This means that it can do four different computations in parallel, which is pretty amazing considering that 15 years ago, a single-core CPU was the default and even two cores were only for enthusiasts.

But even back then, you were not limited to doing only a single task at a time, right? You could listen to music and browse the internet at the same time, even on a single-core CPU. How does your CPU manage to pull that off? Well, the same way your brain does. It juggles tasks. When you're reading a book while listening to your friend talking, part of the time, you're not reading, and part of the time, you're not listening – that is, until we get at least two cores in our brains.

The servers you run your code on have pretty much the same...

Introducing coroutines

In addition to the threading model provided by Java, Kotlin also has a coroutines model. Coroutines might be considered lightweight threads, and we'll see what advantages they provide over an existing model of threads shortly.

The first thing you need to know is that coroutines are not part of the language. They are simply another library provided by JetBrains. For that reason, if we want to use them, we need to specify this in our Gradle configuration file; that is, build.gradle.kts:

dependencies { 
    ... 
    implementation("org.jetbrains.kotlinx:kotlinx-      coroutines-core:1.5.1") 
}

Important Note:

By the time you read this book, the latest version of the Coroutines library will be 1.6 or greater.

First, we will compare starting a new thread and a new coroutine.

Starting coroutines

We've already seen how to start a new thread in Kotlin in the...

Summary

In this chapter, we covered how to create threads and coroutines in Kotlin, as well as the benefits of coroutines over threads.

Kotlin has simplified syntax for creating threads, compared to Java. But it still has the overhead of memory and, often, performance. Coroutines can solve these issues; use coroutines whenever you need to execute some code concurrently in Kotlin.

At this point, you should know how to start a coroutine and how to wait for it to complete, getting its results in the process. We also covered how coroutines are structured and learned about how they interact with dispatchers.

Finally, we touched upon the topic of structured concurrency, a modern idea that helps us prevent resource leaks in concurrent code easily.

In the next chapter, we'll discuss how we can use these concurrency primitives to create scalable and robust systems that suit our needs.

Questions

  1. What are the different ways to start a coroutine in Kotlin?
  2. With structured concurrency, if one of the coroutines fails, all the siblings will be canceled as well. How can we prevent that behavior?
  3. What is the purpose of the yield() function?
lock icon
The rest of the chapter is locked
You have been reading a chapter from
Kotlin Design Patterns and Best Practices - Second Edition
Published in: Jan 2022Publisher: PacktISBN-13: 9781801815727
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Alexey Soshin

Alexey Soshin is a software architect with 15 years of experience in the industry. He started exploring Kotlin when Kotlin was still in beta, and since then has been a big enthusiast of the language. He's a conference speaker, published writer, and the author of a video course titled Pragmatic System Design.
Read more about Alexey Soshin