What does Thread.join() do and how would you wait for sev… — Cracked Java
// Concurrency & Multithreading · Thread Fundamentals & Lifecycle
MidTheory

What does Thread.join() do and how would you wait for several threads?

t.join() makes the calling thread wait (state WAITING) until thread t finishes — i.e. t becomes TERMINATED. It's the simplest "wait for this to be done" primitive. To wait for several threads, you join() each of them, or use a higher-level synchronizer.

What join does

Internally join() is implemented with wait() guarded by isAlive() — when t's run() returns, the JVM calls notifyAll() on the Thread object, waking the joiners. The timed overload join(millis) returns after the deadline whether or not t finished — so you must re-check t.isAlive() to know which happened. join() throws InterruptedException, so the waiter itself can be interrupted.

Thread t = new Thread(() -> doWork());
t.start();
t.join(2000);            // wait up to 2s
if (t.isAlive()) {
    t.interrupt();       // it didn't finish in time
}

Waiting for several threads

The naive approach is to join them in sequence — correct, because the total wait equals the longest thread, not the sum:

List<Thread> workers = IntStream.range(0, 4)
    .mapToObj(i -> new Thread(() -> process(i)))
    .peek(Thread::start)
    .toList();
for (Thread w : workers) {
    w.join();            // returns when ALL are done
}

Better: use the right tool

join() only works on raw Thread objects. With an ExecutorService you'd instead use invokeAll() (blocks until every task completes), awaitTermination() after shutdown(), or CompletableFuture.allOf(...).join(). A CountDownLatch initialized to N, with each worker calling countDown(), lets the coordinator await() once — handy when you don't hold the Thread references. Since Java 21, StructuredTaskScope.join() (JEP) waits for a whole scope of subtasks with proper cancellation.

Mark your status