Invoking start() on a Thread instance initiates a new execution path, allocating a distinct system thread. Once scheduled by the operating system, this newly spawned thread independently executes the logic defined within the run() method. Repeated invocations of start() on the same Thread object trigger an IllegalThreadStateException, as the thread's lifecycle state prohibits re-initialization.
Converse, calling run() directly behaves as a standard synchronous method invocation. It executes the encapsulated logic on the current calling thread rather than spawning a background process. The calling thread remains blocked untill the run() method completes its execution cycle.
Behavioral Comparison Demonstration
class ConcurrentTask implements Runnable {
@Override
public void run() {
System.out.println("Active thread: " + Thread.currentThread().getName());
}
}
public class MethodComparison {
public static void main(String[] args) {
ConcurrentTask task = new ConcurrentTask();
Thread asyncThread = new Thread(task, "async-process");
System.out.println("Active thread: " + Thread.currentThread().getName());
asyncThread.run();
asyncThread.start();
}
}
Execution yields the following sequence:
Active thread: main
Active thread: main
Active thread: async-process
The initial output corresponds to the main method's print statement. The second line demonstrates that directly calling run() executes the task synchronously on the main thread. The final line confirms that start() successfully transitioned the task to the newly created async-process thread.
Underlying Source Code Mechanics
The Thread class implements start() with strict state validation:
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean launched = false;
try {
start0();
launched = true;
} finally {
if (!launched) {
group.threadStartFailed(this);
}
}
}
This implementation verifies the thread is in a pristine initialization state (threadStatus == 0). It registers the object with its associated ThreadGroup before delegating to the native start0() method, which handles OS-level thread creation.
private native void start0();
The run() method lacks thread spawning logic, operating purely as a dispatch mechanism:
public void run() {
if (target != null) {
target.run();
}
}
If the Thread was constructed with a Runnable delegate (target), its specific run() implementation is invoked directly within the caller's execution context. No additional threading infrastructure is engaged.