빠른 비교
Runnable task = () -> {
System.out.println("work on " + Thread.currentThread().getName());
};
Thread thread = new Thread(task, "worker-1");
thread.start();
thread.join();갈리는 기준
어떤 스레드 실행 형태를 먼저 떠올리면 되나
| 상황 | 먼저 떠올릴 선택 |
|---|---|
| 실행할 작업만 분리 | Runnable |
| 실제 스레드 객체를 직접 다룸 | Thread |
| 새 스레드 시작 | start() |
| 현재 스레드에서 그냥 메서드 호출 | run() |
| 실무에서 반복 작업 처리 | 보통 ExecutorService 먼저 고려 |
Thread vs Runnable: 역할 분리
Runnable은 "무슨 일을 할지"를 표현하는 인터페이스이고, Thread는 "그 일을 실제로 실행하는 컨테이너"입니다. 두 역할을 분리하면 작업 로직을 독립적으로 정의하고 재사용하기 쉬워집니다. Thread를 직접 상속하는 방식보다 Runnable이나 Callable로 작업을 분리하는 편이 더 자연스럽습니다.
// Thread 상속 — 작업 로직과 실행이 결합됨
class Worker extends Thread {
@Override
public void run() { doWork(); }
}
// Runnable 분리 — 작업 로직을 별도로 정의
Runnable task = () -> doWork();
Thread thread = new Thread(task, "worker-1");start() vs run(): 새 스레드를 여는 방법
start()를 호출해야 새 Thread가 생성되고 run()이 그 Thread에서 실행됩니다. run()을 직접 호출하면 새 Thread 없이 현재 Thread에서 일반 메서드처럼 실행됩니다. 입문자가 가장 자주 하는 실수입니다.
Thread thread = new Thread(() -> System.out.println("thread: " + Thread.currentThread().getName()));
thread.run(); // ❌ main thread에서 실행 — "thread: main" 출력
thread.start(); // ✅ 새 thread에서 실행 — "thread: Thread-0" 출력Thread lifecycle과 실무 패턴
Thread는 NEW → RUNNABLE → BLOCKED/WAITING → TERMINATED 흐름을 거칩니다. CPU를 계속 잡는다고 항상 빨라지는 것은 아니며, lock 대기나 I/O 대기 상태도 많습니다. 실무에서는 Thread를 직접 많이 만들기보다 ExecutorService가 Thread 수명주기를 관리하게 맡깁니다.
Thread thread = new Thread(task, "worker-1");
thread.start();
thread.join(); // main thread가 worker-1 종료까지 대기
// 실무에서는 ExecutorService가 관리
ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(task);
pool.shutdown();선택 기준
| 상황 | 적합한 선택 |
|---|---|
| 작업 로직 정의 | Runnable (반환값 없음) 또는 Callable (반환값 있음) |
| 새 thread에서 실행 시작 | thread.start() |
| 다른 thread 종료 대기 | thread.join() |
| 다수 thread 관리 | ExecutorService |
| 현재 thread 확인 | Thread.currentThread() |
주의할 점
run()을 직접 호출하면 새 thread가 생기지 않습니다. 비동기 실행 의도라면 반드시 start()를 써야 합니다.
Thread thread = new Thread(() -> {
System.out.println("실행 thread: " + Thread.currentThread().getName());
});
// ❌ run() 직접 호출 — main thread에서 실행됨
thread.run(); // 출력: 실행 thread: main
// ✅ start() 호출 — 새 thread에서 실행됨
thread.start(); // 출력: 실행 thread: Thread-0참고 링크
3 sources