What is the difference between calling start() and calling run() directly on a Thread?
answer
- start() = new thread; run() directly = current thread
- Calling run() = ordinary method call, no concurrency
- start() returns immediately; caller and new thread run in parallel
- Proof: Thread.currentThread().getName() shows main vs Thread-0
- start() once only → second call throws IllegalThreadStateException
basics
~20 sstart() creates a new thread and runs your run() code on it, so it executes concurrently. Calling run() directly just runs the code on the current thread, like an ordinary method call — no new thread, no concurrency.
solid answer
~40 sstart() is the method that actually creates concurrency. It asks the JVM to allocate a new thread, registers it with the scheduler, and that new thread then invokes run(). The calling thread returns from start() immediately and both run in parallel. Calling run() directly is just a normal method call: it executes the run() body synchronously on the current thread, no new thread is spawned, and there is zero concurrency. So if you call run() instead of start(), everything is sequential and 'main' prints, say, the worker's output before continuing. A second consequence: start() may be called only once per Thread object — calling it again throws IllegalThreadStateException — whereas run() is just a method and could be called repeatedly (but pointlessly). This start-vs-run mix-up is a classic interview trap.
code
java · 6 linesRunnable task = () -> System.out.println("running on " + Thread.currentThread().getName());
Thread t = new Thread(task);
t.run(); // prints: running on main (no new thread)
t.start(); // prints: running on Thread-0 (a new thread)
// t.start(); // would throw IllegalThreadStateExceptiongo deeper
State the bottom line: start() spawns a new thread, run() called directly runs on the current thread with no concurrency.
Explain that start() returns immediately and is native, demonstrate the difference with Thread.currentThread().getName(), and know start() is one-shot.
Discuss why the bug is silent (run() compiles and 'works'), the IllegalThreadStateException on re-start, and why this pushes teams toward executors that hide thread lifecycle.
Use it to argue against hand-managed Thread objects entirely: lifecycle correctness (start-once, no restart) is exactly the error-prone surface that ExecutorService / structured concurrency abstract away.
## The two methods A `Thread` object has two relevant methods: - **`run()`** — contains the task. It is an ordinary method whose body is your code. - **`start()`** — the trigger that spawns a *new* thread and arranges for that thread to call `run()`. ## What start() actually does `start()` is native, low-level plumbing. When you call it, the JVM: 1. Creates a new operating-system (or virtual) thread. 2. Marks the Thread object's state as started and hands it to the scheduler. 3. On that **new** thread, invokes `run()`. Meanwhile the **calling** thread does not wait — `start()` returns right away, so the caller and the new thread now run **concurrently**. This is the only way to get a second thread of execution from a Thread object. ## What calling run() directly does `run()` is just a method. If you write `t.run()`, the **current** thread executes the body synchronously, top to bottom, then control returns — exactly like calling any other method. **No new thread is created and there is no concurrency at all.** A quick way to see it: ```java Thread t = new Thread(() -> System.out.println("on " + Thread.currentThread().getName())); t.run(); // prints: on main (runs on the caller's thread) t.start(); // prints: on Thread-0 (runs on a brand-new thread) ``` With `run()` the name is `main`; with `start()` it is a separate thread name — proof that only `start()` switched threads. ## Why people get this wrong Both method names sound like 'go'. But `run()` is the *content* and `start()` is the *engine*. Calling `run()` 'works' (no error, your code executes), which makes the bug silent: the program is simply single-threaded when you expected parallelism. ## One-shot rule A Thread object models one execution. You may call `start()` **at most once**; a second call throws `IllegalThreadStateException`. To run the task again you need a new Thread (or, better, submit the Runnable to a thread pool). `run()`, being a plain method, has no such restriction — but calling it directly is almost always a mistake. ## Takeaway Use `start()` to get concurrency. Calling `run()` directly silently degrades your code to sequential execution on the current thread.
- What happens if you call start() twice on the same Thread object?It throws IllegalThreadStateException. A Thread instance represents a single execution and cannot be restarted; create a new Thread or use a thread pool to run the task again.
- Does calling run() directly ever make sense?Rarely. You might call it from inside your own run() of a subclass, or invoke a Runnable synchronously when you deliberately want no extra thread — but as a way to 'start a thread' it is always a bug.
saying these in an interview costs you the question
- Saying run() starts a new thread — it does not; it runs on the current thread.
- Claiming start() runs run() on the calling thread — it runs run() on the NEW thread.
- Believing you can restart a thread by calling start() again — that throws IllegalThreadStateException.
- Thinking calling run() throws an error so you'd notice — it silently runs single-threaded.