Skip to content

Expert · Multithreading and concurrency · topic 41 of 60 · 25 min

Threads: doing things at the same time

Explanation

A thread is an independent path of execution inside a program. Java programs start with the main thread and can create more with Thread and Runnable, so slow tasks do not block others and multi-core CPUs are used fully. Call start(), not run(), to begin a new thread; join() waits for a thread to finish.

Processes and threads

A process is a running program with its own memory (for example one JVM). A thread is a path of execution inside a process; all threads of a process share its memory (the heap). A web server handles many users at once by running requests on different threads. On a machine with 8 cores, up to 8 threads can truly run at the same moment; with more threads, the operating system switches between them very quickly.

Creating threads

java
Runnable sendReport = () -> {
    System.out.println("Sending report on " + Thread.currentThread().getName());
};

Thread t1 = new Thread(sendReport, "report-thread");
t1.start();                      // a NEW thread runs sendReport
System.out.println("Main continues on " + Thread.currentThread().getName());
t1.join();                       // wait until t1 finishes (throws InterruptedException)
System.out.println("Report done");
The order of the first two lines can differ between runs: the threads run concurrently.

start() versus run()

start() asks the JVM to create a new thread, which then calls run(). Calling run() yourself just runs the code in the CURRENT thread, like any normal method call; no new thread is created. This is a classic interview question.

java
Thread t = new Thread(() -> System.out.println(Thread.currentThread().getName()));
t.run();     // prints "main": no new thread!
t.start();   // prints something like "Thread-0"
// t.start(); // calling start twice throws IllegalThreadStateException

Thread states

StateMeaning
NEWCreated, start() not yet called
RUNNABLERunning or ready to run
BLOCKEDWaiting to enter a synchronized block held by another thread
WAITING / TIMED_WAITINGWaiting for another thread (join, wait) or for time (sleep)
TERMINATEDFinished

sleep, interrupt and daemon threads

java
Thread poller = new Thread(() -> {
    while (!Thread.currentThread().isInterrupted()) {
        System.out.println("Checking for new orders…");
        try {
            Thread.sleep(2000);                    // pause this thread for 2 s
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();    // restore the flag and stop
        }
    }
});
poller.setDaemon(true);   // daemon threads do not keep the JVM alive
poller.start();
// later: poller.interrupt();   // the polite way to ask a thread to stop
Careful: Threads make bugs that appear only sometimes: output in a different order, wrong totals once in a thousand runs. Never assume an order between threads unless you enforce it (join, locks, futures). And do not create a new Thread for every small task in a server; thread creation is costly and unbounded threads can exhaust memory. Use thread pools (topic 3) or virtual threads (topic 5).
Think of it like this: A process is a restaurant; threads are its cooks working in the same kitchen and sharing the same fridge (memory). More cooks finish more orders at once, but if two of them grab the last tomato at the same moment without talking, there will be trouble (next topic).
Tip: Name your threads (new Thread(task, "invoice-worker")). Thread dumps and logs become much easier to read when something hangs in production.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Threads: doing things at the same time · 1/6

Threads

In this lesson you will run code on several threads at once.

Prefer a video by a teacher? Find free videos on “java multithreading tutorial thread runnable start vs run join” on YouTube ↗

In real life: Keeping an app responsive

A desktop billing app used by a pharmacy freezes for 10 seconds while generating a monthly PDF report on the main (UI) thread. Moving the report generation to a background thread keeps the window responsive, and the app shows "Report ready" when the worker finishes.

java
Thread worker = new Thread(() -> {
    byte[] pdf = ReportService.generateMonthly("2026-10");
    Files.write(Path.of("report-2026-10.pdf"), pdf);   // (exception handling omitted)
    System.out.println("Report ready");
}, "report-worker");
worker.start();   // the UI thread continues immediately

Practice (0/3 done)

Task 1 · Question

What is printed? Thread t = new Thread(() -> System.out.print(Thread.currentThread().getName())); t.run();

Task 2 · Question

What happens when start() is called twice on the same Thread object?

Task 3 · Practice

Write a program that starts three threads, each printing its name and a counter from 1 to 5 with a 100 ms sleep. The main thread must wait for all three with join() and then print "All done". Run it several times and note that the interleaving changes.

Quick quiz

Question 1

1.Which is shared between threads of one Java process?

Question 2

2.What does t.join() do?

Question 3

3.What is the polite way to ask a thread to stop?

Question 4

4.Does a daemon thread keep the JVM running?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Which is shared between threads of one Java process?

Answer: The heap (objects)

Objects on the heap are shared; local variables live on each thread's own stack.

What does t.join() do?

Answer: Waits until t finishes

The calling thread waits.

What is the polite way to ask a thread to stop?

Answer: interrupt(), and the thread checks its interrupted flag

Thread.stop is deprecated and unsafe.

Does a daemon thread keep the JVM running?

Answer: No

The JVM exits when only daemon threads remain.

What happens to running threads when main returns?Related

Answer: The program exits and they are stopped

Join threads whose work must complete.

From Threads

In which Java version did virtual threads become a final (non-preview) feature?Related

Answer: Java 21

JEP 444, Java 21.

From Virtual threads (Java 21)

Why use std::lock_guard instead of calling m.lock() and m.unlock() yourself?Related

Answer: It unlocks automatically, even when an exception is thrown (RAII)

Manual unlock is easy to miss on an early return or exception.

From Concurrency 1: threads, mutexes and data races

Which is the correct way to wait inside a coroutine?Related

Answer: delay(1000)

delay suspends only the coroutine.

From Why coroutines? suspend functions

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 4 more topics in “Multithreading and concurrency” before its exam: Race conditions and synchronized, Executors, futures and CompletableFuture, Atomic variables and concurrent collections, Virtual threads (Java 21).
  2. Module 9 exam: Multithreading and concurrency · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, JDBC, Maven, Gradle and JUnit. 60 topics left in the course before the final exam.

← Previous: Reading and writing files