스레드 생성
스레드 생성과 실행은 Thread 클래스와 Runnalbe 인터페이스를 통해 이루어집니다.
1. Thread 클래스를 상속받아 생성하기
- Thread 클래스를 상속하여 새로운 스레드를 생성하는 방법입니다.
- Thread 클래스의 run() 메서드를 오버라이드하여, 스레드가 수행할 작업을 정의합니다.
- start() 메서드를 호출하면 새로운 스레드가 생성되어 run() 메서드를 실행합니다.
2. Runnable 인터페이스를 구현하여 생성하기
- Runnable 인터페이스를 구현하여 스레드를 생성하는 방법입니다.
- run() 메서드를 오버라이드하여 스레드가 수행할 작업을 정의합니다.
- Thread 클래스의 생성자에 Runnable을 구현한 객체를 전달하여 스레드를 생성하고, start() 메서드를 호출하여 실행합니다.
스레드 생성 방법의 비교
| 방법 | 장점 | 단점 |
| Thread 클래스 상속 | 간단하게 스레드를 정의하고 사용할 수 있음 | 다른 클래스 상속이 불가하므로 확장성 부족 |
| Runnable 인터페이스 구현 | 다른 클래스를 상속할 수 있어 더 유연한 설계 가능 | 약간의 코드가 더 필요함 |
구구단
// Gugudan.java
public class Gugudan extends Thread {
private int dan;
// 생성자: 구구단의 단을 받아 초기화
public Gugudan(int dan) {
this.dan = dan;
}
// 스레드가 실행될 때 구구단 출력
@Override
public void run() {
System.out.println(getName() + " 시작");
for (int i = 1; i <= 9; i++) {
System.out.println(dan + " * " + i + " = " + (dan * i));
}
System.out.println(getName() + " 끝");
}
}
package com.exam4;
public class ThreadEx {
public static void main(String[] args) {
// 스레드를 이용하여 3단과 6단 출력
Gugudan gugudan1 = new Gugudan(3);
Gugudan gugudan2 = new Gugudan(6);
gugudan1.start();
gugudan2.start();
}
}
스레드 상태
- NEW (새로운 상태): 스레드가 생성된 후 아직 start() 메서드가 호출되지 않은 상태입니다.
- RUNNABLE (실행 가능 상태): start() 메서드가 호출되어 CPU에서 실행 대기 중인 상태입니다. 운영체제의 스케줄러가 CPU를 할당하면 RUNNING 상태로 변경됩니다.
- BLOCKED (차단 상태): 스레드가 잠금(lock)을 기다리고 있는 상태입니다. 자원을 획득하지 못해 실행되지 못하고 대기하는 상황입니다.
- WAITING (대기 상태): 스레드가 특정 조건을 만족하기 전까지 대기해야 하는 상태입니다. 예를 들어, 다른 스레드가 작업을 완료할 때까지 대기하는 경우가 이에 해당됩니다.
- TIMED_WAITING (시간 지정 대기 상태): 지정된 시간이 경과할 때까지 대기 상태에 있는 경우입니다. sleep()이나 wait(timeout) 메서드를 통해 이 상태로 진입할 수 있습니다.
- TERMINATED (종료 상태): 스레드의 작업이 완료되어 종료된 상태입니다. 종료된 스레드는 다시 시작할 수 없습니다
우선순위 스레드
우선순위(Thread Priority)는 여러 스레드가 동시에 실행될 때 어떤 스레드를 더 우선적으로 실행할지 결정하는 기준이 됩니다. Java에서 스레드는 기본적으로 동일한 우선순위를 가지고 실행되지만, 특정 스레드에 우선순위를 부여하여 운영체제가 우선적으로 실행하도록 유도할 수 있습니다. Java에서는 Thread 클래스의 setPriority 메서드를 통해 스레드의 우선순위를 설정할 수 있습니다.
우선순위 값의 범위
Java에서 스레드의 우선순위는 1부터 10까지의 정수 값으로 설정할 수 있습니다.
- MIN_PRIORITY (1): 최저 우선순위
- NORM_PRIORITY (5): 기본 우선순위 (디폴트)
- MAX_PRIORITY (10): 최고 우선순위
일반적으로 우선순위가 높은 스레드가 더 자주 CPU 시간을 할당받아 먼저 실행될 가능성이 큽니다.
우선순위의 한계
- 운영체제 의존적: 스레드 우선순위 설정은 운영체제의 스케줄러에 의존합니다. Java에서 우선순위를 설정하더라도 모든 운영체제가 이를 반드시 반영하지 않기 때문에, 우선순위가 높은 스레드가 항상 먼저 실행되는 것은 아닙니다.
- 비결정적 실행: 우선순위는 실행될 가능성을 높여주지만, 실행 순서를 완전히 보장하지 않습니다. 특히, 멀티코어 시스템에서는 각 코어에서 병렬로 실행되기 때문에 실행 순서는 예측하기 어렵습니다.
- 다른 스레드 제어 방식과 병행: 우선순위는 효율적인 CPU 사용을 위한 보조적 방법일 뿐이며, 필요에 따라 join(), sleep(), wait() 등 다른 스레드 제어 방법과 병행하여 사용해야 할 때가 많습니다.
예제 : 구구단 출력에 우선순위 적용
public class GugudanPriority extends Thread {
...
public static void main(String[] args) {
GugudanPriority g3 = new GugudanPriority(3);
GugudanPriority g6 = new GugudanPriority(6);
g3.setPriority(Thread.MIN_PRIORITY); // 3단: 최저 우선순위
g6.setPriority(Thread.MAX_PRIORITY); // 6단: 최고 우선순위
g3.start();
g6.start();
}
}
Thread 메서드
1. Thread.currentThread() : 현재 실행 중인 스레드를 반환하는 메서드로, 현재 스레드의 정보를 참조할 수 있도록 합니다.
public class ThreadEx03 {
public static void main(String[] args) {
// 현재 실행 중인 스레드의 우선순위 확인
System.out.println("Current thread priority: " + Thread.currentThread().getPriority());
// 현재 실행 중인 스레드의 개수 출력
System.out.println("Active thread count: " + Thread.activeCount());
// 현재 스레드를 참조하는 객체 생성
Thread current = Thread.currentThread();
// 현재 스레드 정보 출력
System.out.println("Current thread: " + current); // 스레드 객체 출력
System.out.println("Thread name: " + current.getName()); // 스레드 이름 출력
System.out.println("Is thread alive: " + current.isAlive()); // 스레드가 활성 상태인지 확인
System.out.println("Is daemon thread: " + current.isDaemon()); // 데몬 스레드 여부 확인
}
}
2. Thread.sleep(long millis) : 현재 스레드를 지정된 시간 동안 일시 정지 시키는 메서드입니다. 주어진 시간만큼 스레드가 일시 중단되었다가, 시간이 지나면 자동으로 실행 대기 상태로 돌아갑니다.
- 예외처리 : sleep()메서드는 InterruptedException을 발생시킬 수 있으므로, 이를 처리하기 위해 try-catch 블록으로 감싸는 것이 일반적입니다.
public class ThreadEx04 {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(i); // 현재 숫자 출력
try {
Thread.sleep(1000); // 1초 동안 일시정지
} catch (InterruptedException e) {
System.out.println("[에러] " + e.getMessage());
}
}
}
}
데몬 스레드
1. 일반 스레드 (User Thread)
- 정의: 일반 스레드는 프로그램의 주요 작업을 수행하며, 프로그램 종료 시까지 실행 상태를 유지합니다. 모든 일반 스레드가 종료되어야 프로그램이 완전히 종료됩니다.
- 특징:
- 일반 스레드는 기본적으로 Thread 클래스를 통해 생성
- 주요 작업을 담당 : 파일 읽기/쓰기, 네트워크 요청 등 프로그램의 핵심 작업을 담당하며, 중요한 역할을 수행하는 스레드
- 프로그램 종료 여부에 영향 : 일반 스레드가 하나라도 실행 중이면 프로그램은 종료되지 않음.
스레드는 자바에서 작업의 실행 단위로서, 여러 작업을 병렬로 수행할 수 있게 하는 기능입니다. 자바에서는 일반 스레드와 **데몬 스레드(Daemon Thread)**로 스레드를 구분할 수 있으며, 각 스레드는 프로그램의 실행과 종료에 다른 역할을 합니다.
2. 데몬 스레드 (Daemon Thread)
- 정의: 데몬 스레드는 백그라운드에서 보조적인 작업을 수행하며, 일반 스레드가 모두 종료되면 자동으로 종료됩니다. 일반 스레드의 작업을 돕거나, 유지보수에 필요한 작업을 수행하지만, 단독으로 프로그램 종료를 막지는 않습니다.
- 특징:
- 백그라운드 작업 : 가비지 컬렉터, 자동 저장, 로그 기록 등 백그라운드에서 계속 실행되다가, 메인 작업이 종료되면 자동으로 종료
- 자동 종료 : 프로그램의 모든 일반 스레드가 종료되면, 데몬 스레드도 자동으로 종료
- 설정 방법 : setDaemon(true)메서드를 통해 데몬 스레드로 설정할 수 있습니다. 단, 스레드 시작 전에 설정해야 하며, 시작 후에는 변경할 수 없음.
데몬 스레드 예제
// 구구단 스레드 작동 반복의 수가 컴퓨터 성능보다 충분히 크다면 실행 중간에 종료
package com.exam6;
public class ThreadEx {
public static void main(String[] args) {
// 스레드를 이용하여 3단과 6단 출력
Gugudan gugudan1 = new Gugudan(3); // 3단 스레드 생성
Gugudan gugudan2 = new Gugudan(6); // 6단 스레드 생성
// 두 스레드를 데몬 스레드로 설정
gugudan1.setDaemon(true);
gugudan2.setDaemon(true);
// 스레드 이름 설정
gugudan1.setName("3단");
gugudan2.setName("6단");
// 스레드 시작
gugudan1.start();
gugudan2.start();
// 메인 스레드가 10밀리초 대기 후 종료
try {
Thread.sleep(10); // 메인 스레드가 10ms만 대기
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 메인 스레드 종료 후 데몬 스레드들도 자동으로 종료
}
}
중간에 출력이 끊기는 이유
- 데몬 스레드는 모든 일반 스레드가 종료되면 자동으로 종료됩니다.
- 이 코드에서는 메인 스레드가 10밀리초만 대기하고 종료되므로, 두 구구단 스레드는 구구단을 모두 출력하기 전에 종료됩니다.
- 따라서 결과적으로 구구단의 일부만 출력되고, 메인 스레드가 종료되면서 데몬 스레드들도 중단되기 때문에 출력이 중간에 끊기게 됩니다.
'Backend > Java' 카테고리의 다른 글
| [Java]java.net 패키지 : InetAddress/URL/URLConnection 클래스 (0) | 2024.11.01 |
|---|---|
| 공유 자원의 문제와 동기화 (0) | 2024.11.01 |
| [Java]Enum(열거형) (2) | 2024.10.31 |
| [Java] 커넥션 풀 (0) | 2024.10.31 |
| [Java] 중첩클래스 (0) | 2024.10.31 |