Java 28: Thread, Runnable & Thread.start vs run
easy⏱ 5 mincoursejava
Thread vs Runnable
Runnable = the work (void run()). Thread = the executor. new Thread(runnable).start() creates a new thread and invokes runnable.run() on it. Prefer Runnable over extending Thread — composition over inheritance, and the same runnable can be passed to any executor.
// Preferred — Runnable
Runnable work = () -> System.out.println("hi from " + Thread.currentThread().getName());
new Thread(work, "worker-1").start();
start() vs run()
t.start() spawns a new OS thread and schedules run on it. t.run() is a plain method call — it runs on the current thread. If you write t.run() thinking you started a thread, you'll get fully sequential execution. t.start() can only be called once per Thread — calling it twice throws IllegalThreadStateException.
Thread states
NEW → RUNNABLE → (BLOCKED / WAITING / TIMED_WAITING) ↔ RUNNABLE → TERMINATED. BLOCKED: waiting for a monitor lock. WAITING: wait()/join(). TIMED_WAITING: sleep(ms)/wait(ms). Thread.getState() returns the current state — great for debugging deadlocks.
Simulate start vs run
Build a SimThread that records which 'virtual OS thread' it ran on. start() assigns a new thread id; run() uses the current 'main' thread id. Run three tasks via start and three via run; log the thread id each task saw.
Name your threads
new Thread(r, "order-processor") — give every thread a name. Thread dumps become readable: "pool-2-thread-3" is useless; "order-processor-3" tells you exactly what was running. ThreadFactory sets this for pools.
Quiz: Can you restart a Thread?
Can you call thread.start() twice? No. Once terminated, a Thread is unusable — you have to create a new one. If you need repeated work, use an ExecutorService and submit tasks to it.