kotlinx.coroutines.delay() vs Thread.sleep()
Tags: kotlin, beginners, android, programming
Published: 2022-04-29 23:53:48

**Simple and beginner-friendly Kotlin code examples to show the different behavior of using kotlinx.coroutines.delay() and Thread.sleep()**

This is part of the Kotlin coroutines series:
* [Part 1 - Kotlin Coroutines Basics - Simple Android App Demo](https://vtsen.hashnode.dev/kotlin-coroutines-basics-simple-android-app-demo)    
* **Part 2 - kotlinx.coroutines.delay() vs Thread.sleep()**   
* [Part 3 - GlobalScope vs viewModelScope vs lifecycleScope vs rememberCoroutineScope](https://vtsen.hashnode.dev/globalscope-vs-viewmodelscope-vs-lifecyclescope-vs-remembercoroutinescope)    
* [Part 4 - launchWhenCreated() vs launchWhenStarted() vs launchWhenResumed() vs repeatOnLifeCycle()](https://vtsen.hashnode.dev/launchwhencreated-vs-launchwhenstarted-vs-launchwhenresumed-vs-repeatonlifecycle)


`kotlinx.coroutines.delay()` is a suspend function. It doesn't block the current thread. `Thread.sleep()` blocks the current thread. It means other code in this thread won't be executed until `Thread.sleep()` is exited.

## Example 1 - kotlinx.coroutines.delay()
```kotlin
fun main(args: Array<String>) {
    runBlocking {
            run()
        }
    }
}

suspend fun run() {
    coroutineScope {
        val timeInMillis = measureTimeMillis {
            val mainJob = launch {
                //Job 0
                launch {
                    print("A->")
                    delay(1000)
                    print("B->")
                }
                //Job 1
                launch {
                    print("C->")
                    delay(2000)
                    print("D->")
                }
                //Job 2
                launch {
                    print("E->")
                    delay(500)
                    print("F->")
                }

                //Main job
                print("G->")
                delay(1500)
                print("H->")
            }

            mainJob.join()
        }

        val timeInSeconds =
            String.format("%.1f", timeInMillis/1000f)
        print("${timeInSeconds}s")
   }
}
```

**Main job** will run first and then will be suspended by `delay()` suspend function, followed by **Job 0 -> Job 1 -> Job 2**.  All jobs are suspended and kicked off at around the same time.  Then, the shortest `delay()` will be run first. The `timeinSeconds` to complete all the jobs should be the longest `delay()` which is 2 seconds.

The output looks like this:
```
G->A->C->E->F->B->H->D->2.0s
```

This is pretty easy to understand. What if we replace `delay(2000)` with `Thread.Sleep(2000)` for **Job1**?

## Example 2 - Thread.sleep() on Dispatchers.Main

```kotlin
suspend fun run() {
    coroutineScope {
        val timeInMillis = measureTimeMillis {
            val mainJob = launch {
                //Job 0
                launch {
                    print("A->")
                    delay(1000)
                    print("B->")
                }
                //Job 1
                launch {
                    print("C->")
                    Thread.sleep(2000)
                    print("D->")
                }
                //Job 2
                launch {
                    print("E->")
                    delay(500)
                    print("F->")
                }

                //Main job
                print("G->")
                delay(1500)
                print("H->")
            }

            mainJob.join()
        }

        val timeInSeconds =
            String.format("%.1f", timeInMillis/1000f)
        print("${timeInSeconds}s")
   }
}
```
Similar to example 1 above, **Main job** will run first and suspended by `delay()` suspend function, followed by **Job 0 → Job 1**.  **Job 0** will be suspended. However, when `Thread.sleep(2000)` is run on **Job 1**, the thread will be blocked for 2 seconds. **Job 2** at this time is not executed.

After 2 seconds, **D** will be printed out first, followed by **E** in **Job 2**. **Job 2** then will be suspended.  Because **Main job** and **Job 0** are suspended less than 2 seconds, it will run immediately. **Job 0** will run first because the suspend time is shorter.

After 0.5 seconds, **Job 2** is resumed and completed. It will print out **F**.

**Timestamp #1 (after 0 second)**
- **Main job** and **Job 0** are started and suspended. 
- **Job 1** is started and blocks the thread

**Timestamp #2 (after 2 seconds)** 
- **Job 1** is done
- **Job 2** is started and suspended.
- **Job 0** and **Main job** are resumed and done.

**Timestamp #3 (after 0.5 seconds)**
- **Job 3** are resumed and done

So the total time consumes is around 2.5 seconds.

The output looks like this:
```
G->A->C->D->E->B->H->F->2.5s
```

## Example 3 - Thread.sleep() on Dispatchers.Default/IO

Wait, what if run the `run` suspend function in background thread using `Dispatchers.Default` or `Dispatchers.IO`.  For example:
```kotlin
runBlocking {
	withContext(Dispatchers.Default) {
		run()
	}
}
```
The output becomes like this:
```
A->C->G->E->F->B->H->D->2.0s
```
The output is similar to Example 1 above, where `Thread.sleep()` doesn't seem to block the thread! Why? 

When `Dispatchers.Default` or `Dispatchers.IO` is used, it is backed by a pool of threads. Each time we call `launch{}`, a different worker thread is created / used. 

For example, here are the worker threads being used:

- Main job - DefaultDispatcher-worker-1
- Job 0 - DefaultDispatcher-worker-2
- Job 1 - DefaultDispatcher-worker-3
- Job 2 - DefaultDispatcher-worker-4

> To see which thread is currently running, you can use `println("Run ${Thread.currentThread().name}")`

So `Thread.sleep()` indeed blocks that thread, but only blocks the  `DefaultDispatcher-worker-3`. The other jobs can still be continued to run since they're on different threads.

**Timestamp #1 (after 0 second)**
- **Main job**, **Job 0**, **Job 1** and **Job 2** are started. Sequence can be random. See Note(1) below.
- **Main job**, **Job 0** and **Job2 ** are suspended. 
- **Job 1 ** blocks its own thread.

**Timestamp #2 (after 0.5 second)** 
- **Job 2** is resumed and done.

**Timestamp #3 (after 1 second)**
- **Job 0** are resumed and done

**Timestamp #4 (after 1.5 seconds)**
- **Main job** are resumed and done

**Timestamp #5 (after 2 seconds)**
- **Job 1** are resumed and done

> Because each job runs on a different thread, the job can be started at different time. So the output of A, C, E, G could be random. Thus, you see the initiat job starting sequence is different than the one in Exampe 1 above.


## When to use Thread.Sleep()?
`Thread.Sleep()` is almost useless because most of the time we don't want to block the thread. `kotlinx.coroutines.delay()` is recommended. 

I personally use `Thread.Sleep()` to simulate long-running task that block the thread. It is useful to test whether I have put the long-running task into the background thread. If I run it from the main UI thread, the UI won't be responsive.

If I call this `simulateBlockingThreadTask()` in the main UI thread, it will block the main UI thread. The application will crash with non-responsive UI.

```kotlin
private suspend fun simulateBlockingThreadTask() {
        Thread.sleep(2000)
 }
```

However, if we switch the thread to background thread using `kotlinx.coroutines.withContext()`, calling this `simulateBlockingThreadTask()` from the main UI thread won't crash the application.

```kotlin
private suspend fun simulateBlockingThreadTask() {
    withContext(Dispatchers.Default) {
        Thread.sleep(2000)
    }
}
```
## Remember to use yield()

In my previous example in [Coroutines Basics](https://vtsen.hashnode.dev/kotlin-coroutines-basics-simple-android-app-demo) blog post, I used `yield()` to break out the `Thread.sleep()` to basically allow the coroutine to be cancellable.  It is generally a good practice not to block the UI thread for too long. 

In the code example, I simulate both blocking and non-blocking thread tasks. The total running time is 400 milliseconds.

```kotlin
private suspend fun simulateLongRunningTask() {
	simulateBlockingThreadTask()
	simulateNonBlockingThreadTask()
}

private suspend fun simulateBlockingThreadTask() {
	repeat(10) {
		Thread.sleep(20)
		yield()
	}
}

private suspend fun simulateNonBlockingThreadTask() {
	delay(200)
}
```

## Conclusion
`Thread.sleep()` blocks the thread and `kotlinx.coroutines.delay()` doesn't. 

I use `Thread.sleep()` to test whether I have properly put the long-running task into background thread. Other than this, I can't think of any reasons we want to use `Thread.sleep()`.

---

*Originally published at [https://vtsen.hashnode.dev](https://vtsen.hashnode.dev/kotlinxcoroutinesdelay-vs-threadsleep)*.