In Java programs, there are situations when a thread is executing too fast or the program needs to switch to another thread. To do this, you need to suspend the execution of the current thread. In Java, this can be done using the java lang Thread sleep() method.

Java Thread sleep() method

The Thread class is present in the Java.lang package and contains the Thread.sleep() method. Java.lang.thread sleep() method is used to suspend the current thread for a specified amount of time in milliseconds. If you look at Oracle docs, you will find that there are two overloaded sleep() methods of the Thread class.

static void sleep(long millis)
where millis is the time in milliseconds. This method causes the currently executing thread to sleep (temporarily stop execution, “sleeping”) for the millis of milliseconds, depending on the precision of the system timers and schedulers. The argument value for milliseconds can’t be negative. If so, the IllegalArgumentException will be thrown.

static void sleep(long millis, int nanos)
where mills it the time in milliseconds and nanos is the time in nanoseconds. This variant of method is used to suspend the execution of the current thread for the exact time in milliseconds and nanoseconds. The nanosecond value is valid between 0 and 999999. Let's create a simple program that uses the Thread.sleep() method to pause the execution of the main thread for 5 seconds:

public class SleepDemo {

       public static void main(String[] args) throws InterruptedException {
           //the current time in milliseconds
           long start = System.currentTimeMillis();
           // stop the main thread of the program for 5000 milliseconds (5 seconds)
           Thread.sleep(5000);
           System.out.println("The thread is paused for " + (System.currentTimeMillis() - start) + " milliseconds");
       }
}
What's going on in this program? First it starts, then it’s sleeping for 5 milliseconds (5 seconds), then prints to the console a message about how long it was frozen, and then exits. The output is:
The thread is paused for 5008 milliseconds
As you can see, the program did not pause for 5 seconds, but a little bit longer. Also if you run the program on your computer, you will notice that it could stop the execution of the thread for a longer than 5000 milliseconds and not necessary for 5008 milliseconds. The point is that it all depends on the operating system and the specific implementation of the thread scheduler. In a little more detail, the actual time a thread waits before waking up and starting execution depends on the system timers and schedulers. For a quiet system, the actual sleep time is close to the specified sleep time, but for a loaded system it will be slightly longer. This method is often used in child threads when you need to do some action all the time, but not too often. Here is an example of a program that will print a message every second and never exit:

public class SleepDemo1 {

   public static void main(String[] args) throws InterruptedException {
       while (true)
       {
           Thread.sleep(1000);
           System.out.println("One more second");
       }
   }
}

Important points of Java Thread Sleep

It is important to remember that the Java Thread Sleep method works in such a way that:
  • It always suspends the execution of the current thread.

  • The actual thread sleeps until it wakes up, and the execution time depends on the system timers and schedulers.

  • The sleeping thread does not block the current thread.

  • Any other thread can interrupt the current sleeping thread, in which case an InterruptedException is thrown.

  • The argument value for milliseconds cannot be negative, otherwise an IllegalArgumentException will be thrown.

To give an example of throwing an IllegalArgumentException, just modify the above program a bit:

public class SleepDemo1 {

       public static void main(String[] args) throws InterruptedException {
           //the current time in milliseconds
           long start = System.currentTimeMillis();
           // stop the main thread of the program for 5000 milliseconds (5 seconds)
           Thread.sleep(-5000);
           System.out.println("The thread is paused for " + (System.currentTimeMillis() - start) + " ms");
       }
}
Here is the output:
Exception in thread "main" java.lang.IllegalArgumentException: timeout value is negative at java.base/java.lang.Thread.sleep(Native Method) at SleepDemo.main(SleepDemo.java:7)
Above we put the main thread to sleep. Now let's try to apply the method to some other thread.

// Java Program to sleep the custom thread
public class SleepDemo2 extends Thread{

       public void run()
       {
           // thread 0
           try {
               for (int i = 0; i < 10; i++) {

                   // sleeps the main thread for about 2 seconds
                   Thread.sleep(2000);
                   System.out.println(i);
               }
           }
           catch (Exception e) {

               // catching the exception
               System.out.println(e);
           }
       }
       public static void main(String[] args)
       {
           SleepDemo2 sleepDemo2 = new SleepDemo2();
           sleepDemo2.start();
       }
}
The output is:
0 1 2 3 4 5 6 7 8 9

Potential Pitfalls When Using Thread.sleep()

Although Thread.sleep() is commonly used, it comes with several pitfalls that developers should be aware of to avoid unexpected behavior and runtime issues.

1. InterruptedException

One of the most common pitfalls when using Thread.sleep() is failing to handle the InterruptedException. This checked exception is thrown when a thread is interrupted during its sleep period.

try {
    Thread.sleep(1000); // Sleep for 1 second
} catch (InterruptedException e) {
    System.out.println("Thread was interrupted: " + e.getMessage());
    // Handle the interruption appropriately
}

Tip: Always handle the InterruptedException gracefully to ensure your application’s flow is not disrupted unexpectedly.

2. Overusing Thread.sleep()

Over-relying on Thread.sleep() for task scheduling or synchronization can lead to inefficient and unresponsive code. It's important to consider alternatives like ScheduledExecutorService for more precise control.

3. Impact on Multithreading

Using Thread.sleep() in a multithreaded environment can cause race conditions or deadlocks if not used carefully. Always ensure proper synchronization and avoid assumptions about other threads' states.

4. Miscalculating Sleep Duration

Setting an inappropriate sleep duration can either delay task execution unnecessarily or fail to provide sufficient pause. Be mindful of the duration to ensure optimal performance.

5. Ignoring Time Units

The sleep duration is specified in milliseconds. Developers may accidentally provide values assuming seconds, leading to unexpected behavior. For example:

// Incorrect: Assumes 10 seconds but pauses for 10 milliseconds
Thread.sleep(10);

Best Practices for Using Thread.sleep()

To use Thread.sleep() effectively, follow these best practices:

1. Use TimeUnit for Readability

Instead of hardcoding sleep durations, use the TimeUnit class for better readability and maintainability:

import java.util.concurrent.TimeUnit;

try {
    TimeUnit.SECONDS.sleep(1); // Sleep for 1 second
} catch (InterruptedException e) {
    System.out.println("Thread was interrupted: " + e.getMessage());
}

2. Handle Interruption Gracefully

Always handle interruptions properly to maintain application stability:

try {
    Thread.sleep(500);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt(); // Restore the interrupted status
    System.out.println("Thread interrupted. Cleaning up...");
}

3. Avoid Using Thread.sleep() for Precise Timing

For tasks requiring precise timing, use scheduled executors or timer-based mechanisms:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.schedule(() -> {
    System.out.println("Task executed after 1 second");
}, 1, TimeUnit.SECONDS);
scheduler.shutdown();

4. Minimize Usage in Critical Sections

Avoid using Thread.sleep() inside critical sections or synchronized blocks, as it can lead to thread contention and degraded performance.

5. Use Logging for Debugging

If you use Thread.sleep() for debugging purposes, ensure it is accompanied by logging and remove it before deploying the code to production:

System.out.println("Simulating delay...");
Thread.sleep(2000);