개발/자바
Thread 설정 및 주요 메서드
피터JK
2025. 2. 17. 14:22
728x90

Java에서 Thread 관련 설정 및 주요 메서드를 정리해 보겠습니다.
1. Thread 생성 및 실행 방법
(1) Thread 클래스를 상속하여 생성
class MyThread extends Thread {
public void run() {
System.out.println("Thread 실행 중...");
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 새로운 스레드 시작
}
}
(2) Runnable 인터페이스를 구현하여 생성
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable 실행 중...");
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
2. 주요 메서드
| 메서드 | 설명 |
| start() | 새로운 스레드를 생성하고 실행 (run() 호출) |
| run() | 스레드 실행 로직 (직접 호출하면 단순한 메서드 실행) |
| join() | 해당 스레드가 종료될 때까지 현재 스레드 대기 |
| sleep(ms) | 현재 스레드를 지정된 밀리초(ms) 동안 정지 |
| interrupt() | 스레드 중단 요청 (예외 발생 가능) |
| isInterrupted() | 스레드가 인터럽트 상태인지 확인 |
| yield() | 실행 중인 스레드를 일시적으로 멈추고 다른 스레드에게 CPU 양보 |
| setDaemon(true) | 데몬 스레드로 설정 (메인 스레드 종료 시 자동 종료) |
| getName() | 스레드 이름 가져오기 |
| setName("이름") | 스레드 이름 설정 |
| getId() | 스레드 고유 ID 가져오기 |
| getState() | 현재 스레드 상태 가져오기 |
| getPriority() | 스레드 우선순위 가져오기 (1~10) |
| setPriority(int) | 스레드 우선순위 설정 (기본값: 5) |
3. Thread 상태 (Lifecycle)
스레드는 아래의 6가지 상태를 가질 수 있습니다.
| 상태 | 설명 |
| NEW | start() 호출 전 (아직 실행되지 않음) |
| RUNNABLE | 실행 가능한 상태 (CPU 점유 대기) |
| BLOCKED | 다른 스레드가 자원을 점유 중이라 대기 |
| WAITING | wait() 호출로 무기한 대기 |
| TIMED_WAITING | sleep(ms), join(ms), wait(ms) 호출로 일정 시간 대기 |
| TERMINATED | 스레드 종료 상태 |
🔹 스레드 상태 확인
System.out.println(thread.getState()); // 현재 스레드 상태 출력
4. Thread 우선순위 설정
스레드는 기본적으로 5의 우선순위를 가지며, 1~10까지 설정 가능함.
Thread thread = new Thread(new MyRunnable());
thread.setPriority(Thread.MAX_PRIORITY); // 10
thread.setPriority(Thread.MIN_PRIORITY); // 1
thread.setPriority(Thread.NORM_PRIORITY); // 5 (기본값)
👉 하지만 OS 스케줄러가 결정하기 때문에 반드시 높은 우선순위가 먼저 실행된다는 보장은 없음.
5. Thread 동기화 (Synchronization)
멀티스레드 환경에서는 공유 자원 보호를 위해 동기화가 필요합니다.
(1) synchronized 키워드 사용
class SharedResource {
synchronized void printMessage(String message) {
System.out.println(message);
}
}
(2) ReentrantLock 사용
import java.util.concurrent.locks.ReentrantLock;
class SharedResource {
private final ReentrantLock lock = new ReentrantLock();
void printMessage(String message) {
lock.lock();
try {
System.out.println(message);
} finally {
lock.unlock();
}
}
}
6. Thread 종료 방법
(1) interrupt() 활용
class MyThread extends Thread {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Thread 실행 중...");
}
System.out.println("Thread 종료됨");
}
}
🔹 interrupt() 호출 시 isInterrupted()가 true가 되어 루프 종료
(2) volatile 플래그 활용
class MyThread extends Thread {
private volatile boolean running = true;
public void run() {
while (running) {
System.out.println("Thread 실행 중...");
}
System.out.println("Thread 종료됨");
}
public void stopThread() {
running = false;
}
}
🔹 volatile 변수 변경을 통해 안전한 종료 가능
7. 데몬 스레드
- setDaemon(true)를 설정하면 메인 스레드 종료 시 자동 종료됨.
- 주로 백그라운드 작업에 사용됨 (ex. GC, 로그 처리).
class MyDaemonThread extends Thread {
public void run() {
while (true) {
System.out.println("데몬 스레드 실행 중...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
}
public static void main(String[] args) {
MyDaemonThread thread = new MyDaemonThread();
thread.setDaemon(true);
thread.start();
try { Thread.sleep(3000); } catch (InterruptedException e) {}
System.out.println("메인 스레드 종료");
}
}
📌 주의: 데몬 스레드는 finally 블록이 실행되지 않을 수 있음.
8. Thread Pool (ExecutorService) 활용
스레드를 효율적으로 관리하려면 Thread Pool을 사용하는 것이 좋음.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class MyTask implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName() + " 실행 중...");
}
}
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3); // 3개의 스레드 풀 생성
for (int i = 0; i < 5; i++) {
executor.submit(new MyTask());
}
executor.shutdown(); // 작업 종료
}
}
✅ 장점:
✔️ 직접 Thread 객체를 생성하지 않아도 됨
✔️ 스레드 재사용 가능 (비용 절감)
✔️ 동시 실행 제한 가능
9. Callable과 Future (값 반환)
- Runnable은 반환값이 없지만, Callable은 값 반환 가능.
import java.util.concurrent.*;
class MyCallable implements Callable<String> {
public String call() {
return "Callable 실행 완료!";
}
}
public class CallableExample {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new MyCallable());
System.out.println(future.get()); // 결과 반환
executor.shutdown();
}
}
📌 get()은 결과가 나올 때까지 블로킹됨.
결론
- Thread vs Runnable → Runnable 권장
- synchronized vs ReentrantLock → ReentrantLock이 더 유연함
- interrupt() vs volatile → 둘 다 종료에 활용 가능
- 직접 Thread 생성 vs ExecutorService → Thread Pool이 효율적
- Runnable vs Callable → Callable은 값 반환 가능
💡 멀티스레드는 성능 최적화뿐만 아니라 동기화 문제도 신경 써야 하므로 주의가 필요합니다! 🚀
728x90