Unravel › Java concepts › Concurrency
Threads and shared state
A thread is an independent path of execution.
At a glance
Several cooks working in one kitchen with one set of ingredients.
- 1new Thread(task).start() begins a new thread that runs taskCalling run() directly does not start a thread; it just runs the code on the current one.
- 2join() waits for a thread to finish, and Thread.sleep pauses the current threadBoth throw InterruptedException, which means "someone asked this thread to stop".
- 3Threads share heap memoryIf two threads read and change the same variable without coordination, results depend on timing (a race condition).
- 4Modern Java (21+) offers virtual threads: cheap threads for blocking code, created with Thread.ofVirtual() or Executors.newVirtualThreadPerTaskExecutor()
- When you catch InterruptedException, either rethrow it or call Thread.currentThread().interrupt() to restore the flag; swallowing it makes the thread impossible to stop cleanly
- A platform thread maps to an operating system thread with its own stack (about 1 MB by default)
Thread worker = new Thread(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // keep the stop request alive }}, "report-worker");worker.start();worker.join();- line 1 uses Thread, the core of Threads and shared state
- line 3 uses Thread, the core of Threads and shared state
- line 5 keep the stop request alive
- line 8 uses start, the core of Threads and shared state
- line 9 uses join, the core of Threads and shared state
Read the full explanation (about 1 min)
A thread is an independent path of execution. Several threads run at the same time inside one program and share its memory, which is powerful and the root of most concurrency bugs.
A mental model
Several cooks working in one kitchen with one set of ingredients. They finish faster, but two cooks reaching for the last egg at the same moment is a problem someone has to prevent.
How it works
new Thread(task).start() begins a new thread that runs task. Calling run() directly does not start a thread; it just runs the code on the current one.
join() waits for a thread to finish, and Thread.sleep pauses the current thread. Both throw InterruptedException, which means "someone asked this thread to stop".
Threads share heap memory. If two threads read and change the same variable without coordination, results depend on timing (a race condition).
Modern Java (21+) offers virtual threads: cheap threads for blocking code, created with Thread.ofVirtual() or Executors.newVirtualThreadPerTaskExecutor().
Going deeper
When you catch InterruptedException, either rethrow it or call Thread.currentThread().interrupt() to restore the flag; swallowing it makes the thread impossible to stop cleanly. Creating a raw thread per task does not scale; use an executor. Prefer immutable data and message passing over shared mutable state.
Under the hood
A platform thread maps to an operating system thread with its own stack (about 1 MB by default). The scheduler switches between them, so execution order is not under your control, and the Java Memory Model defines when one thread's writes become visible to another.
Common mistakes
- Calling
run()instead ofstart(). - Swallowing
InterruptedException. - Unsynchronised access to shared variables.
- Creating unlimited threads.
How Unravel recognises it
When you paste code, Unravel looks for these signs of threads and shared state. Spotting them yourself is a good habit when you read unfamiliar code:
- Types:
ThreadThreadLocal - Method calls:
start()join()interrupt()sleep()isInterrupted()currentThread()startVirtualThread()ofVirtual() - Created with new:
Thread
Part of a learning path
Related concepts
Builds on this
Frequently asked questions
What is Threads and shared state?
A thread is an independent path of execution. Several threads run at the same time inside one program and share its memory, which is powerful and the root of most concurrency bugs.
What are the most common mistakes with Threads and shared state?
Calling run() instead of start(). Swallowing InterruptedException. Unsynchronised access to shared variables. Creating unlimited threads.
How can I see Threads and shared state in real code?
Paste your own Java into Unravel and it will point out where threads and shared state appears, explain how it works at the detail level you choose, and draw the flow of the code around it.