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.
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.
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.
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.
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.
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.
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.sleepwhen the requirement is delayed execution rather than blocking the current thread. - Catching
InterruptedExceptionand 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
ScheduledExecutorServiceafter scheduling background work.
Summary
- Use
Thread.sleeporTimeUnit.sleepwhen you truly want to block the current thread. - Use
ScheduledExecutorServicewhen 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.

