Java
Programming
Coding
Delay Function
Software Development

How do I make a delay in Java?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Java, a “delay” can mean either blocking the current thread for some amount of time or scheduling work to run later without blocking the caller. Those are different requirements, and the right API depends on which one you actually mean.

Pause the Current Thread with Thread.sleep

For the simplest case, use Thread.sleep.

java
1public class SleepDemo {
2    public static void main(String[] args) {
3        try {
4            System.out.println("Start");
5            Thread.sleep(1500);
6            System.out.println("Finished after delay");
7        } catch (InterruptedException e) {
8            Thread.currentThread().interrupt();
9            System.out.println("Interrupted while sleeping");
10        }
11    }
12}

This blocks the current thread for roughly 1.5 seconds. It does not pause every thread in the JVM; it affects only the thread executing that code.

For readability, many teams prefer TimeUnit when the delay is naturally expressed in seconds or minutes.

java
import java.util.concurrent.TimeUnit;

TimeUnit.SECONDS.sleep(2);

That is still a blocking sleep, but the units are clearer than a raw millisecond literal.

Always Handle Interruption Correctly

Thread.sleep throws InterruptedException. In most application code, you should restore the interrupt flag after catching it.

java
1catch (InterruptedException e) {
2    Thread.currentThread().interrupt();
3    return;
4}

Ignoring interruption can break cooperative cancellation and make shutdown behavior unreliable. That matters on servers, worker pools, and any program that expects tasks to stop cleanly.

Schedule Work Instead of Blocking

If the real requirement is “run this later,” do not sleep the current thread just to wait. Use ScheduledExecutorService.

java
1import java.util.concurrent.Executors;
2import java.util.concurrent.ScheduledExecutorService;
3import java.util.concurrent.TimeUnit;
4
5public class ScheduleDemo {
6    public static void main(String[] args) {
7        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
8
9        scheduler.schedule(() -> System.out.println("Ran later"), 2, TimeUnit.SECONDS);
10
11        scheduler.shutdown();
12    }
13}

This lets the submitting thread continue immediately while the scheduler manages the delayed task.

For repeated work, you can choose between fixed-rate and fixed-delay scheduling.

java
scheduler.scheduleAtFixedRate(() -> System.out.println("tick"), 0, 5, TimeUnit.SECONDS);

Use fixed rate when you want a regular cadence. Use fixed delay when each run should wait until the previous run finishes.

Delay in Concurrent Workflows

Sometimes the best delay is part of a larger async flow rather than a direct sleep. A scheduler can complete a future later while the rest of the application keeps moving.

java
1import java.util.concurrent.CompletableFuture;
2
3CompletableFuture<String> future = new CompletableFuture<>();
4scheduler.schedule(() -> future.complete("ready"), 1, TimeUnit.SECONDS);
5future.thenAccept(System.out::println);

That pattern is more flexible than sleeping a worker thread, especially in services or pipelines where responsiveness matters.

Avoid Sleeping the Wrong Thread

Thread.sleep is often misused in places where blocking is harmful. Examples include:

  • UI threads in Swing or JavaFX
  • request threads in web applications
  • shared executor threads
  • asynchronous pipelines that should stay responsive

Sleeping those threads can freeze the interface, reduce throughput, or hide a design problem. In those contexts, delayed scheduling or a nonblocking workflow is usually the right answer.

The same warning applies to tests. A sleep can make a flaky test pass sometimes, but it often just masks timing uncertainty. Waiting on a real signal, latch, or future is more reliable.

Common Pitfalls

  • Using Thread.sleep when the requirement is delayed execution rather than blocking the current thread.
  • Catching InterruptedException and swallowing it without restoring the interrupt status.
  • Sleeping on UI or request-handling threads and making the program unresponsive.
  • Using arbitrary sleeps in tests instead of synchronizing on the real completion condition.
  • Forgetting to shut down a ScheduledExecutorService after scheduling background work.

Summary

  • Use Thread.sleep or TimeUnit.sleep when you truly want to block the current thread.
  • Use ScheduledExecutorService when work should happen later without blocking the caller.
  • Treat interruption as part of the control flow, not as noise to ignore.
  • Avoid sleeping threads that need to stay responsive.
  • A good Java delay solution depends on whether you need a pause or a scheduler.

Course illustration
Course illustration

All Rights Reserved.