Why we call Thread.start method which in turns calls run method?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In Java, run() contains the code a thread should execute, but start() is what actually creates a new thread of execution. That distinction is not ceremony. It is how the JVM asks the operating system to schedule work on a separate call stack. Calling run() directly is just an ordinary method call on the current thread.
start() creates a real concurrent thread
When you call start(), the JVM transitions the thread from the NEW state into a runnable state and arranges for the new thread to invoke run().
You will usually see different thread names, which shows that the work really moved onto another thread.
Calling run() directly does not start a thread
If you call run() yourself, Java treats it as a normal method call:
Both lines execute on the main thread. No scheduler involvement, no new call stack, and no concurrency.
That is why Java exposes both methods. run() defines the task. start() begins threaded execution of that task.
The separation reflects thread lifecycle
A Thread object has a lifecycle. Roughly speaking:
- new: object created, not started
- runnable:
start()called, eligible for execution - running or blocked: managed by the scheduler
- terminated:
run()finished
If run() alone started a new thread, the JVM would have no clean place to separate "what the thread should do" from "when the thread should actually begin."
This separation also lets the runtime enforce important rules. For example, a thread can be started only once.
That restriction makes sense only because start() is a lifecycle operation, not just another method call.
Why this matters in real code
Using run() accidentally instead of start() causes subtle bugs:
- expected parallel work runs serially
- UI or request threads stay blocked
- concurrency bugs disappear during testing because no real concurrency happened
That last point is particularly dangerous. Code may look correct in a small example because everything runs on one thread, then fail later when real threading is introduced.
Runnable makes the design clearer
Modern Java often separates the task from the thread object by using Runnable or executors:
Or with an executor:
These APIs reinforce the same idea: the code to run is one thing, and the mechanism that schedules it on a thread is another.
Common Pitfalls
The most common mistake is calling run() directly and assuming it creates concurrency. It does not.
Another common issue is treating start() as if it were just a convenience wrapper around run(). It is a lifecycle operation with JVM and scheduler involvement.
People also forget that a Thread can be started only once. If work must run again, create a new thread or use an executor.
Finally, raw Thread usage is often less maintainable than ExecutorService for real applications that need pooling, cancellation, or back-pressure.
Summary
- '
run()defines the work;start()begins a new thread that will execute that work.' - Calling
run()directly is just a normal method call on the current thread. - '
start()exists to manage thread lifecycle and scheduling.' - A thread can be started only once.
- In modern Java,
Runnableand executors usually express the design more clearly than subclassingThread.

