Two ways to make a thread: extend Thread or implement Runnable (prefer Runnable).
start() launches a new thread; run() just calls the method on the current thread (classic trap).
The “multiple threads on one object” memory: with Runnable, many threads can share one Runnable instance (one task object, one shared state); extending Thread ties task+thread together.
Two ways to create a thread
1. Extend Thread:
class Cook extends Thread { public void run() { System.out.println("chopping"); }}new Cook().start();
Java allows only single inheritance — extend Thread and you’ve used up your one extends; Runnable is an interface, so your class stays free to extend something else.
Separation of concerns — Runnable = the task; Thread = the worker. Cleaner: the task doesn’t need to know it’s a thread.
Reuse with pools — ExecutorService takes Runnable/Callable, not Thread subclasses.
The “multiple threads on one object” memory (your Stack Overflow recollection)
This is the real distinction you were reaching for:
With Runnable, you can hand the same Runnable instance to many Thread objects — multiple threads running over one shared task object:
Runnable shared = new Counter(); // ONE objectnew Thread(shared).start(); // thread Anew Thread(shared).start(); // thread B → both share Counter's state
If Counter has mutable fields, now you have shared mutable state → races. This is the setup where thread-safety bites.
With extends Thread, each thread is its own object; you typically get one thread per object, and sharing state means extra wiring.
So the concept: Runnable decouples the task from the thread, which is exactly what lets several threads operate on a single shared task object.
start() vs run() — the trap
start() → asks the JVM to create a new thread, which then calls run(). Real concurrency.
run() → just a normal method call on the current thread. No new thread. Looks like it works, runs sequentially.
Test Yourself
Runnable vs extending Thread — why prefer Runnable?::Single inheritance stays free; separates task from worker; works with thread pools/Executors.
start() vs run()?::start() launches a new thread that calls run(); calling run() directly just runs it on the current thread — no concurrency.
How can multiple threads run over one object?::Pass the same Runnable instance to several Thread objects — they share that task object’s state (and its race risks).