HomeAndroidkotlinx.coroutines.delay() vs Thread.sleep()

kotlinx.coroutines.delay() vs Thread.sleep()


kotlinx.coroutines.delay() is a droop perform. It would not block the present thread. Thread.sleep() blocks the present thread. It means different code on this thread will not be executed till Thread.sleep() is exited.

Instance 1 – kotlinx.coroutines.delay()

enjoyable principal(args: Array<String>) {
    runBlocking {
            run()
        }
    }
}

droop enjoyable 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->")
                }

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

            mainJob.be a part of()
        }

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

Predominant job will run first after which will likely be suspended by delay() droop perform, adopted by Job 0 -> Job 1 -> Job 2. All jobs are suspended and kicked off at across the similar time. Then, the shortest delay() will likely be run first. The timeinSeconds to finish all the roles ought to be the longest delay() which is 2 seconds.

The output seems to be like this:

G->A->C->E->F->B->H->D->2.0s

That is fairly straightforward to grasp. What if we change delay(2000) with Thread.Sleep(2000) for Job1?

Instance 2 – Thread.sleep() on Dispatchers.Predominant

droop enjoyable 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->")
                }

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

            mainJob.be a part of()
        }

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

Much like instance 1 above, Predominant job will run first and suspended by delay() droop perform, adopted by Job 0 Job 1. Job 0 will likely be suspended. Nevertheless, when Thread.sleep(2000) is run on Job 1, the thread will likely be blocked for two seconds. Job 2 presently isn’t executed.

After 2 seconds, D will likely be printed out first, adopted by E in Job 2. Job 2 then will likely be suspended. As a result of Predominant job and Job 0 are suspended lower than 2 seconds, it would run instantly. Job 0 will run first as a result of the droop time is shorter.

After 0.5 seconds, Job 2 is resumed and accomplished. It’ll print out F.

Timestamp #1 (after 0 second)

  • Predominant job and Job 0 are began and suspended.
  • Job 1 is began and blocks the thread

Timestamp #2 (after 2 seconds)

  • Job 1 is finished
  • Job 2 is began and suspended.
  • Job 0 and Predominant job are resumed and achieved.

Timestamp #3 (after 0.5 seconds)

  • Job 3 are resumed and achieved

So the whole time consumes is round 2.5 seconds.

The output seems to be like this:

G->A->C->D->E->B->H->F->2.5s

Instance 3 – Thread.sleep() on Dispatchers.Default/IO

Wait, what if run the run droop perform in background thread utilizing Dispatchers.Default or Dispatchers.IO. For instance:

runBlocking {
    withContext(Dispatchers.Default) {
        run()
    }
}

The output turns into like this:

A->C->G->E->F->B->H->D->2.0s

The output is much like Instance 1 above, the place Thread.sleep() would not appear to dam the thread! Why?

When Dispatchers.Default or Dispatchers.IO is used, it’s backed by a pool of threads. Every time we name launch{}, a special employee thread is created / used.

For instance, listed here are the employee threads getting used:

  • Predominant job – DefaultDispatcher-worker-1
  • Job 0 – DefaultDispatcher-worker-2
  • Job 1 – DefaultDispatcher-worker-3
  • Job 2 – DefaultDispatcher-worker-4

To see which thread is presently working, you should use println("Run ${Thread.currentThread().identify}")

So Thread.sleep() certainly blocks that thread, however solely blocks the DefaultDispatcher-worker-3. The opposite jobs can nonetheless be continued to run since they’re on completely different threads.

Timestamp #1 (after 0 second)

  • Predominant job, Job 0, Job 1 and Job 2 are began. Sequence will be random. See Word(1) under.
  • Predominant job, Job 0 and Job2 are suspended.
  • Job 1 blocks its personal thread.

Timestamp #2 (after 0.5 second)

  • Job 2 is resumed and achieved.

Timestamp #3 (after 1 second)

  • Job 0 are resumed and achieved

Timestamp #4 (after 1.5 seconds)

  • Predominant job are resumed and achieved

Timestamp #5 (after 2 seconds)

  • Job 1 are resumed and achieved

As a result of every job runs on a special thread, the job will be began at completely different time. So the output of A, C, E, G may very well be random. Thus, you see the initiat job beginning sequence is completely different than the one in Exampe 1 above.

When to make use of Thread.Sleep()?

Thread.Sleep() is sort of ineffective as a result of more often than not we do not need to block the thread. kotlinx.coroutines.delay() is beneficial.

I personally use Thread.Sleep() to simulate long-running job that block the thread. It’s helpful to check whether or not I’ve put the long-running job into the background thread. If I run it from the principle UI thread, the UI will not be responsive.

If I name this simulateBlockingThreadTask() in the principle UI thread, it would block the principle UI thread. The appliance will crash with non-responsive UI.

personal droop enjoyable simulateBlockingThreadTask() {
        Thread.sleep(2000)
 }

Nevertheless, if we swap the thread to background thread utilizing kotlinx.coroutines.withContext(), calling this simulateBlockingThreadTask() from the principle UI thread will not crash the appliance.

personal droop enjoyable simulateBlockingThreadTask() {
    withContext(Dispatchers.Default) {
        Thread.sleep(2000)
    }
}

Keep in mind to make use of yield()

In my earlier instance in Coroutines Fundamentals weblog put up, I used yield() to interrupt out the Thread.sleep() to mainly enable the coroutine to be cancellable. It’s usually an excellent apply to not block the UI thread for too lengthy.

Within the code instance, I simulate each blocking and non-blocking thread duties. The entire working time is 400 milliseconds.

personal droop enjoyable simulateLongRunningTask() {
    simulateBlockingThreadTask()
    simulateNonBlockingThreadTask()
}

personal droop enjoyable simulateBlockingThreadTask() {
    repeat(10) {
        Thread.sleep(20)
        yield()
    }
}

personal droop enjoyable simulateNonBlockingThreadTask() {
    delay(200)
}

Conclusion

Thread.sleep() blocks the thread and kotlinx.coroutines.delay() would not.

I exploit Thread.sleep() to check whether or not I’ve correctly put the long-running job into background thread. Aside from this, I can not consider any causes we need to use Thread.sleep().

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments