51. Creating and Starting Threads
Java threads can be created by subclassing Thread or implementing Runnable; always call start() (not run()) to launch a new OS thread; daemon threads do not prevent JVM shutdown.
Explanation
Two classic approaches: extend Thread and override run(), or implement Runnable and pass it to Thread. The Runnable approach is preferred โ it keeps the task separate from the thread lifecycle and allows the task class to extend something else.
start() vs run(): start() creates a new OS thread and asynchronously calls run() on it. Calling run() directly just executes the method synchronously on the current thread โ no new thread is created. This is the most common threading mistake.
Daemon threads: a daemon thread (thread.setDaemon(true) before start()) does not prevent the JVM from exiting when all non-daemon threads finish. Daemon threads are abruptly stopped when the JVM shuts down โ never use them for tasks that must complete (I/O, database writes). The main thread and threads it starts are non-daemon by default.
Example
public class ThreadCreateStart {
// Option 1: extend Thread (tightly coupled โ less preferred)
static class CounterThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(getName() + " count: " + i);
}
}
}
// Option 2: Runnable (preferred โ decoupled)
static class CounterTask implements Runnable {
private final String name;
CounterTask(String name) { this.name = name; }
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(name + " count: " + i);
}
}
}
public static void main(String[] args) throws InterruptedException {
// start() โ correct: launches new thread
Thread t1 = new CounterThread();
t1.start();
// Runnable + Thread constructor
Thread t2 = new Thread(new CounterTask("t2"));
t2.start();
// Lambda as Runnable (most concise modern style)
Thread t3 = new Thread(() -> System.out.println("Lambda thread: " + Thread.currentThread().getName()));
t3.start();
// Daemon thread: will be killed if main ends first
Thread daemon = new Thread(() -> {
try { Thread.sleep(5000); System.out.println("Daemon done (may never print)"); }
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
});
daemon.setDaemon(true);
daemon.start();
// join: wait for t1 and t2 to finish
t1.join();
t2.join();
t3.join();
System.out.println("All threads finished");
}
}Sources
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Thread.html โ Thread API
- https://docs.oracle.com/javase/tutorial/essential/concurrency/threads.html โ Concurrency tutorial