Limited Offer
60% OFF on all plans!

Concurrency & Delay in Java

Run parallel work with threads, Runnable, Callable, ExecutorService, CompletableFuture, and schedule delayed or periodic tasks with ScheduledExecutorService.

Waiting & Delay

1. Wait for N Milliseconds

`Thread.sleep(ms)` pauses the current thread for the given number of milliseconds. It throws `InterruptedException` which must be handled.

2. Run a Function Asynchronously

Use `CompletableFuture.runAsync()` to run code in the background without blocking the main thread.

Parallel Execution

1. Creating and Running Threads

Create threads by passing a `Runnable` lambda. Call `start()` — not `run()` — to run on a new OS thread.

2. ExecutorService — Thread Pool

Creating raw threads for every task is expensive. `ExecutorService` manages a pool of reusable threads. Use `Executors.newFixedThreadPool(n)` for a fixed pool size.

Coordinating Async Operations

1. Wait for Multiple Async Tasks

`CompletableFuture.allOf()` waits for all given futures to complete — equivalent to `Promise.all()` in JavaScript.

2. Wait for At Least One Task

`CompletableFuture.anyOf()` completes as soon as the fastest future completes — equivalent to `Promise.race()` in JavaScript.

3. Chaining Async Operations (thenApply)

`thenApply()` chains transformations on a future result — equivalent to `.then()` in JavaScript Promises.

CompletableFuture Chaining: thenAccept, thenRun & exceptionally

1. thenAccept() — Consuming the Result

`thenAccept(consumer)` runs a callback with the result when the future completes — does not return a new value.

2. thenRun() — Cleanup / Side Effect

`thenRun(runnable)` runs a callback after the future completes but does not receive the result — useful for cleanup.

3. exceptionally() — Handling Errors

`exceptionally(fn)` catches any exception in the chain and returns a fallback value — equivalent to `.catch()` in JavaScript Promises.

4. whenComplete() — then + catch Combined

`whenComplete(biConsumer)` runs after the future completes — either with a result or an exception. Both are passed as arguments.

5. Chaining Style vs get() Blocking

Prefer chaining callbacks over calling `.get()` to avoid blocking the current thread.

Passing Data Between Async & Sync Code

1. Passing Data from an Async Function

`CompletableFuture.supplyAsync()` returns a future carrying the result. Use `join()` or `thenAccept()` to retrieve it.

Timers & Intervals

1. Run After Delay (setTimeout equivalent)

`ScheduledExecutorService.schedule()` runs a task once after a specified delay.

2. Run at Every Interval (setInterval equivalent)

`scheduleAtFixedRate()` runs a task repeatedly at a fixed interval.

Measuring Time

1. Calculating Time Interval

Use `System.currentTimeMillis()` or `System.nanoTime()` to measure elapsed time. Prefer `nanoTime()` for short durations.

Thread Safety & Synchronization

1. Race Condition Problem

When multiple threads modify shared state without coordination, results become unpredictable — this is called a race condition.

2. Fix with AtomicInteger

`AtomicInteger` from `java.util.concurrent.atomic` provides thread-safe integer operations without explicit locking.

3. Fix with synchronized

The `synchronized` keyword locks a method or block so only one thread can execute it at a time.

4. Deadlock

A deadlock occurs when two or more threads are each waiting for a lock held by the other — they block forever. Fix by always acquiring locks in a consistent order.