Explanation
What just happened
new Thread(...) only built an object. start() asked the operating system for a real thread, and that thread ran download() while main kept going. main finished first, but the program didn’t end: the JVM waited for worker.
Try the what-if switch
- run() by mistake:
run()is just the method that holds your code. Calling it runsdownload()on main, like any other method. Nothing runs in parallel and worker staysNEW. - daemon thread: the JVM doesn’t wait for daemon threads. When main ends, worker is stopped mid-download, and its
finallyblocks never run.
The rule
| Call | Runs on | main waits? |
|---|---|---|
start() |
the new thread | no |
run() |
the caller | yes, it’s a plain call |
The JVM exits when the last non-daemon thread ends. Daemons are for background helpers whose work can be thrown away, like a cache cleaner.
In real code
You rarely create threads by hand. An ExecutorService reuses a few threads for many tasks, and the next scenarios use one. But every executor does exactly this underneath: it calls start() once per thread, then feeds it tasks.
Common questions
What is the difference between start() and run() in Java?
start() runs your code on a new thread and returns at once. run() is a plain method call: the code runs on the calling thread, nothing runs in parallel, and the thread stays NEW.
Can I call start() twice on the same thread?
No. A second start() throws IllegalThreadStateException, even after the thread has finished. Create a new Thread, or use an executor.
Does the JVM wait for daemon threads before it exits?
No. The JVM exits when the last non-daemon thread ends, and daemon threads are stopped wherever they are. Mark a thread with setDaemon(true) before calling start().
Verified: this timeline matches a real program, checked in CI on JDK 21 and 25. How we verify. Unclear or wrong? Tell us