Thread

The Thread class maps directly to the programming concept of a thread of execution within a programming language. Multiple threads can be run at the same time. Therefore, we can create new threads to run code in a non-blocking way. Let's look at a simple example.

To start, we'll define a function called threadExample():

fun threadExample() {
println("Running threadExample()")

println("Finished threadExample()")
}

Within that function, we've added log statements for when the function begins and ends. These are to help illustrate the non-blocking nature of the eventual Thread usage.

Next, we'll create, and start, a new Thread class:

fun threadExample() {
println("Running threadExample()")
val thread = Thread {
Thread.sleep(1000)

println("Thread finished after 1 second")
}
thread.start()

println("Finished threadExample()")
}

Within the lambda of the Thread initialization, we have called Thread.sleep(1000), which will delay the finish of that Thread by 1 second. Once the Thread has been declared, we call start() to begin execution of that Thread.

If we invoke threadExample() from our main function, we can examine the output:

fun main() {
println("Hello Chapter 10")
threadExample()
}

After running the preceding code, we'll receive the following output:

Hello Chapter 10
Running threadExample()
Finished threadExample()
Thread finished after 1 second

From this output, we can see that the log statement from our new Thread is the last thing printed out to the console. This is because that Thread was delayed, while the initial Thread continued with its execution.

While quite simple, this example demonstrates one of the core challenges in asynchronous programming. With our threadExample() function, our Thread was created and started before the Finished threadExample() log message was executed. However, println("Finished threadExample()") is run before the thread has finished executing. To ensure that our original thread doesn't complete until our new Thread has finished executing, we would require additional blocking mechanisms, which become challenging to write, test, and maintain.

Threads provide a means of executing an independent piece of code without blocking the current thread of execution. There are challenges associated with using threads, however. Creating a new Thread is a relatively expensive operation when executing your program, and having too many threads can potentially strain system resources. We'll explore one possible solution to this challenge in the next section.