자바의 정석[기초편]으로 공부한 내용을 정리한 글입니다.
main 쓰레드
main 쓰레드란?
- 자바 프로그램에서 main() 메서드를 실행하는 기본 쓰레드
- 이 쓰레드는 프로그램 시작과 동시에 만들어져 main()의 코드를 실행함
쓰레드의 종류
자바에서는 쓰레드가 2종류로 나뉩니다:
사용자 쓰레드 | 일반적으로 우리가 생성하는 쓰레드 (main, new Thread(...)) |
데몬 쓰레드 | 백그라운드에서 동작하는 보조 쓰레드 (ex. GC 쓰레드) |
프로그램 종료 조건
"실행 중인 사용자 쓰레드가 하나도 없을 때 프로그램은 종료된다."
즉, 데몬 쓰레드가 아무리 남아 있어도,
사용자 쓰레드가 전부 종료되면 프로그램은 끝납니다.
- main 쓰레드 = 사용자 쓰레드
- 사용자 쓰레드가 다 끝나면 = 프로그램 종료
- call stack에 run()이 실행되고 있는 사용자 쓰레드가 하나라도 있으면 → 종료되지 않음
- 아무 사용자 쓰레드도 없을 때 → 프로그램 완전히 종료됨
쓰레드 종료 기다리기 – join()
문제 상황
- main() 쓰레드가 다른 쓰레드(th1, th2)를 시작하자마자 System.out.print()로 넘어가면
→ 소요 시간을 측정할 때 아직 다른 쓰레드가 종료되지 않았는데 출력이 될 수 있음
해결 방법: join() 메서드
th1.join(); // main 쓰레드는 th1이 끝날 때까지 기다림
th2.join(); // th2도 끝날 때까지 기다림
join()은 “이 쓰레드가 끝날 때까지 기다려라”라는 의미
- main 쓰레드가 join() 없이 출력할 경우 → 소요시간이 조기 출력됨 ❌
- join을 써서 th1, th2를 모두 기다리면 → 소요시간 정확하게 출력됨 ⭕
- 실제 실행 결과도 |, - 등이 출력되다가 마지막에 "소요시간: ...", "프로그램 종료" 출력됨
싱글 쓰레드 vs 멀티 쓰레드
싱글 쓰레드
for (...) { System.out.print("-"); }
for (...) { System.out.print("|"); }
- 모든 작업이 순차적으로 진행됨
- main이 A작업(-), B작업(|)을 순서대로 진행
멀티 쓰레드
MyThread1 th1 = new MyThread1();
MyThread2 th2 = new MyThread2();
th1.start();
th2.start();
각 클래스:
class MyThread1 extends Thread {
public void run() {
for (...) System.out.println("-");
}
}
class MyThread2 extends Thread {
public void run() {
for (...) System.out.println("|");
}
}
- 두 쓰레드가 동시에 실행됨
- OS의 스케줄러가 th1, th2에게 CPU를 번갈아 줌
- A와 B가 섞여서 출력됨
싱글 vs 멀티 실행 시간 비교
싱글 쓰레드
- A → B 순서로 하나씩 처리 → 시간 총합이 짧음 (연속 실행)
하단: 멀티 쓰레드
- OS가 th1, th2를 왔다갔다하면서 CPU를 번갈아 줌
- 그 전환(context switching) 자체에 시간 오버헤드가 발생함
따라서 작업이 순차적이고, cpu만 사용하는 계산 위주일 때 싱글 쓰레드가 더 빠름