Java 멀티스레딩 완벽 해설: 개념, 생명주기, 실전 코드 예제
Java 애플리케이션은 종종 여러 작업을 동시에 수행해야 합니다. 이 튜토리얼은 단일 스레드 vs 멀티스레드 실행, 스레드 생명주기, 동기화 기법, 각 개념을 설명하는 실전 코드 예제를 안내합니다.
단일 스레드란?
Java에서 단일 스레드는 가장 작은 실행 단위입니다. Java 런타임은 애플리케이션 시작 시 사용자 스레드를 생성하며, 필요에 따라 추가 사용자 또는 데몬 스레드를 추가할 수 있습니다. 데몬 스레드는 백그라운드에서 실행되며 JVM 종료를 막지 않습니다.
단일 스레드 예제:
package demotest;
public class GuruThread {
public static void main(String[] args) {
System.out.println("Single Thread");
}
}
단일 스레드 실행의 장점:
- 최소 오버헤드 – 실행 컨텍스트가 하나만 유지됨
- 디버깅과 유지보수 단순화
Java에서 멀티스레딩이란?
멀티스레딩은 두 개 이상의 스레드가 동시에 실행되게 하여 CPU 활용도를 극대화합니다. 스레드는 같은 메모리 공간을 공유하므로 컨텍스트 스위칭이 빠르고 메모리 사용량이 낮습니다.
두 개의 동시 스레드 생성 예제:
package demotest;
public class GuruThread1 implements Runnable {
public static void main(String[] args) {
Thread guruThread1 = new Thread("Guru1");
Thread guruThread2 = new Thread("Guru2");
guruThread1.start();
guruThread2.start();
System.out.println("Thread names are following:");
System.out.println(guruThread1.getName());
System.out.println(guruThread2.getName());
}
@Override
public void run() {
// 스레드 로직
}
}
멀티스레딩의 이점:
- 논블로킹 UI 및 백그라운드 처리
- 회복성 – 한 스레드의 예외가 다른 스레드를 멈추지 않음
Java 스레드 생명주기
스레드 생명주기는 다섯 가지 구분된 상태로 구성됩니다:
- New – 스레드 인스턴스화되었으나 시작 안 됨
- Runnable – 스레드 시작됨, 실행 준비 완료
- Running – 스레드 활발히 실행 중
- Waiting – 특정 이벤트 발생까지 일시 중단
- Dead – 스레드 실행 완료
Java 스레드 생명주기
주요 스레드 메서드
| 메서드 | 설명 |
| start() | 스레드 실행 시작; JVM이 run() 호출 |
| sleep(long milliseconds) | 현재 스레드를 지정된 시간 동안 일시 정지 |
| getName() | 스레드 이름 반환 |
| setPriority(int newPriority) | 스레드 우선순위 조정 (1-10) |
| yield() | 스케줄러에게 현재 스레드 양보 제안 |
실전 스레드 예제
아래는 스레드 생성, 우선순위 조정, 슬립을 보여주는 간결한 예제입니다.
package demotest;
public class ThreadExample1 implements Runnable {
@Override
public void run() {
// 스레드 작업
}
public static void main(String[] args) {
Thread guruThread1 = new Thread();
guruThread1.start();
try {
Thread.sleep(1000); // 1초 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
guruThread1.setPriority(1);
System.out.println(guruThread1.getPriority());
System.out.println("Thread Running");
}
}
출력 예:
스레드 동기화
여러 스레드가 공유 자원에 접근할 때 동기화는 데이터 일관성을 보장합니다. Java에서 synchronized 키워드로 임계 영역을 감싸면 독점적 접근을 보장합니다.
synchronized(object) {
// 동기화 블록
}
고급 멀티스레딩 예제
아래는 두 스레드를 생성하여 각각 이름과 카운터를 1초 간격으로 출력하는 더 정교한 예제입니다.
package demotest;
public class GuruThread2 {
public static void main(String[] args) {
GuruThread3 threadGuru1 = new GuruThread3("guru1");
threadGuru1.start();
GuruThread3 threadGuru2 = new GuruThread3("guru2");
threadGuru2.start();
}
}
class GuruThread3 implements Runnable {
private Thread guruthread;
private String guruname;
GuruThread3(String name) {
this.guruname = name;
}
@Override
public void run() {
System.out.println("Thread running " + guruname);
for (int i = 0; i < 4; i++) {
System.out.println(i);
System.out.println(guruname);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Thread has been interrupted");
}
}
}
public void start() {
System.out.println("Thread started");
if (guruthread == null) {
guruthread = new Thread(this, guruname);
guruthread.start();
}
}
}
일반적인 출력 (동반 이미지 참조):
핵심 요약
- 멀티스레딩은 블로킹 호출에서 애플리케이션을 해방하고 동시 연산 가능하게 함
- 스레드 생명주기 – New, Runnable, Running, Waiting, Dead – 스레드가 거치는 상태 정의
- 스레드가 데이터를 공유할 때 동기화 필수, 레이스 컨디션 방지
- 실전 코드 예제로 스레드 생성, 생명주기 관리, 동기화 이해 강화