2024. 10. 2. 01:24ㆍ개발/Java
스레드 그룹
thread.getThreadGroup() 하면 나오는게 스레드 그룹이다. 스레드 그룹은 스레드를 그룹화하여 관리할 수 있다. 기본적으로 모든 스레드는 부모 스레드와 동일한 스레드 그룹에 속하게 된다.
스레드 그룹은 여러 스레드를 하나의 그룹으로 묶어서 특정 작업(예: 일괄 종료, 우선순위 설정)을 수행할 수 있다.
스레드 상태
NEW : 스레드가 아직 시작되지 않은 상태
RUNNABLE : 스레드가 실행 중이거나 실행 가능한 상태
BLOCKED : 스레드가 동기화 락을 기다리는 상태
WAITING : 스레드가 다른 스레드의 특정 작업이 완료되기를 기다리는 상태
TIMED_WAITING : 일정 시간동안 기다리는 상태
TERMINATED : 스레드가 실행을 마친 상태
main 스레드가 thread1, thread2에 어떤 작업을 지시하고 그 결과를 받아서 처리하고 싶다면 어떻게 해야할까?
public class JoinMain {
public static void main(String[] args) {
SumTask task1 = new SumTask(1, 50);
SumTask task2 = new SumTask(51, 100);
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
thread1.start();
thread2.start();
int result1 = task1.result;
int result2 = task2.result;
log("result1 = " + result1);
log("result2 = " + result2);
int sumAll = result1 + result2;
log("sumAll = " + sumAll);
}
static class SumTask implements Runnable {
int startValue;
int endValue;
int result;
public SumTask(int startValue, int endValue) {
this.startValue = startValue;
this.endValue = endValue;
}
@Override
public void run() {
for (int i = startValue; i <= endValue; i++) {
result += i;
}
}
}
}
join() 을 사용한다.
public static void main(String[] args) throws InterruptedException {
SumTask task1 = new SumTask(1, 50);
SumTask task2 = new SumTask(51, 100);
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
int result1 = task1.result;
int result2 = task2.result;
log("result1 = " + result1);
log("result2 = " + result2);
int sumAll = result1 + result2;
log("sumAll = " + sumAll);
}
main 스레드는 thread1이 TERMINATED 상태가 될 때까지 대기(WAITING 상태가 된다.)한다. thread1이 TERMINATED된 것을 확인하면 main 스레드는 RUNNABLE이 되고 thread2.join()이 실행되었으므로 thread2가 TERMINATED 될 때까지 WAITING 상태였다가 TERMINATED 된 것을 확인하면 RUNNABLE이 된다. 하지만 join은 다른 스레드가 종료될 때까지 무제한 기다려야 할 수도 있다. 따라서 join(int millis) 메서드를 사용하면 지정한 시간이 지나면 다시 RUNNABLE 상태가 된다. 이 떄 main 스레드의 상태는 TIMED_WAITING이 되었다가 RUNNABLE이 된다.
Interrupt
스레드가 sleep하고 있을 경우 어떻게 깨워야 할까? 바로 thread.interrupt()를 호출하면 된다. 그러면 thread는 TIMED_WAITING 상태에서 RUNNABLE 상태가 된다.
스레드가 sleep 하고 있을 경우만 interrupt()를 받아들일 수 있는데
다른 부분에서 interrupt()를 받아들이게 하려면 어떻게 해야하는가?
Thread.currentThread().isInterrupted()를 체크해주면 된다.
그리고 isInterrupted()는 예외가 발생하였을 때 false로 바꿔준다. 그 이유는? 스레드의 인터럽트 상태를 정상으로 돌리지 않으면 이후에도 계속 인터럽트가 발생하게 된다.
InterruptedException이 있는 catch문을 타야 Thread.getCurrentThread().isInterrupted가 true에서 false로 바뀌게 된다.
Thread.inturrpted() 와 Thread.*currentThread*().isInterrupted()의 차이?
- Thread.inturrpted()
- 현재 스레드의 interrupt 상태를 확인하고 interrupt가 true일 경우 true를 반환하고 interrupt 상태를 false로 초기화 한다.
- Thread.*currentThread*().isInterrupted()
- 현재 스레드의 interrupt 상태를 확인하지만 interrupt 상태를 변화시키진 않는다.
아래 예제 코드에서 그 차이를 느낄 수 있다.
public class ThreadInterruptMain {
public static void main(String[] args) {
Thread thread = new Thread(new PrintThread2());
thread.start();
log("메인 스레드 시작");
try {
Thread.sleep(1000);
thread.interrupt();
log("thread.isInterrupted() = " + thread.isInterrupted());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class PrintThread implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) { // 인터럽트 상태 변경X
log("작업 중");
}
log("work 스레드 인터럽트 상태2 = " + Thread.currentThread().isInterrupted());
try {
log("자원 정리 시도");
Thread.sleep(1000);
log("자원 정리 완료");
} catch (InterruptedException e) {
log("자원 정리 실패 - 자원 정리 중 인터럽트 발생");
log("work 스레드 인터럽트 상태3 = " +
Thread.currentThread().isInterrupted());
}
log("작업 종료");
}
}
static class PrintThread2 implements Runnable {
@Override
public void run() {
while (!Thread.interrupted()) { // 인터럽트 상태 변경X
log("작업 중");
}
log("work 스레드 인터럽트 상태2 = " + Thread.currentThread().isInterrupted());
try {
log("자원 정리 시도");
Thread.sleep(1000);
log("자원 정리 완료");
} catch (InterruptedException e) {
log("자원 정리 실패 - 자원 정리 중 인터럽트 발생");
log("work 스레드 인터럽트 상태3 = " +
Thread.currentThread().isInterrupted());
}
log("작업 종료");
}
}
}
PrintThread1으로 실행했을 때 로그
2024-10-02 01:21:00.443 [ Thread-0]: 작업 중
2024-10-02 01:21:00.443 [ Thread-0]: 작업 중
2024-10-02 01:21:00.446 [ main]: thread.isInterrupted() = true
2024-10-02 01:21:00.446 [ Thread-0]: work 스레드 인터럽트 상태2 = true
2024-10-02 01:21:00.446 [ Thread-0]: 자원 정리 시도
2024-10-02 01:21:00.446 [ Thread-0]: 자원 정리 실패 - 자원 정리 중 인터럽트 발생
2024-10-02 01:21:00.446 [ Thread-0]: work 스레드 인터럽트 상태3 = false
2024-10-02 01:21:00.446 [ Thread-0]: 작업 종료
PrintThread2로 실행했을 때 로그
2024-10-02 01:18:38.524 [ Thread-0]: 작업 중
2024-10-02 01:18:38.524 [ Thread-0]: 작업 중
2024-10-02 01:18:38.545 [ main]: thread.isInterrupted() = true
2024-10-02 01:18:38.599 [ Thread-0]: work 스레드 인터럽트 상태2 = false
2024-10-02 01:18:38.599 [ Thread-0]: 자원 정리 시도
2024-10-02 01:18:39.604 [ Thread-0]: 자원 정리 완료
2024-10-02 01:18:39.604 [ Thread-0]: 작업 종료
'개발 > Java' 카테고리의 다른 글
Mutex와 Semaphore (0) | 2024.10.20 |
---|---|
메모리 가시성 (0) | 2024.10.20 |
동기화 (0) | 2024.10.05 |
JVM 메모리 영역 (0) | 2024.09.29 |
멀티스레드와 동시성 (0) | 2024.09.24 |