isInterrupted()
public class ThreadStopMainV3 {
public static void main(String[] args) {
MyTask task = new MyTask();
Thread thread = new Thread(task, "work");
thread.start();
sleep(100);
log("작업 중단 지시 thread.interrupt()");
thread.interrupt();
log("work 스레드 인터럽트 상태 1 = " + thread.isInterrupted());
}
static class MyTask 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("작업 종료");
}
}
}
isInterrupted() 메서드는 인터럽트 상태를 확인할 뿐, 인터럽트 상태를 변경하지 않는다. 따라서 여전히 인터럽트 상태가 true인 상태에서 자원 정리가 진행되고, 자원 정리 중에 인터럽트 상태가 ture인데 sleep() 메서드 호출로 인해 InterruptedException이 발생한다(인터럽트 상태일 때 sleep() 메서드를 호출하면 InterruptedException이 발생한다). 즉, 자원 정리 중에 인터럽트로 인해 자원 정리에 실패했다.
자바에서 인터럽트 예외가 한 번 발생하면, 스레드의 인터럽트 상태를 다시 정상(false)으로 돌리는 것이 이런 이유 때문이다. 스레드의 인터럽트 상태를 정상으로 돌리지 않으면 이후에도 계속 인터럽트가 발생하여 예상치 못한 문제가 발생한다. 따라서 인터럽트 목적을 달성하면 인터럽트 상태를 다시 정상으로 돌려두어야 한다.
interrupted()
스레드의 인터럽트 상태를 단순히 확인만 하는 용도라면 Thread.isInterrupted()를 사용하면 된다. 하지만 직접 체크해서 사용할 때는 interrupted()를 사용해야 한다. interrupted()는 다음과 같이 작동한다.
- 스레드가 인터럽트 상태라면 true를 반환하고, 해당 스레드의 인터럽트 상태를 false로 변경한다.
- 스레드가 인터럽트 상태가 아니라면 false를 반환하고, 해당 스레드의 인터럽트 상태를 변경하지 않는다.
public class ThreadStopMainV4 {
public static void main(String[] args) {
MyTask task = new MyTask();
Thread thread = new Thread(task, "work");
thread.start();
sleep(100);
log("작업 중단 지시 thread.interrupt()");
thread.interrupt();
log("work 스레드 인터럽트 상태 1 = " + thread.isInterrupted());
}
static class MyTask implements Runnable {
@Override
public void run() {
while (!Thread.interrupted()) { // 인터럽트 상태 변경 O
log("작업 중");
}
log("work 스레드 인터럽트 상태 2 = " + Thread.currentThread().isInterrupted());
try {
log("자원 정리 시도");
Thread.sleep(1000);
log("자원 정리 완료");
} catch (InterruptedException e) {
log("자원 정리 실패 - 자원 정리 중 인터럽트 발생");
log("work 스레드 인터럽트 상태 3 = " + Thread.currentThread().isInterrupted());
}
log("작업 종료");
}
}
}
위 예제에서는 Thread.isInterrupted() 메서드를 통해 인터럽트 상태가 true에서 false로 변경된다. 따라서 자원 정리 중에 sleep() 메서드가 호출되어도 인터럽트가 발생하지 않는다. 이후에 자원이 정상적으로 정리되었다.
자바는 인터럽트 예외가 한 번 발생하면 스레드의 인터럽트 상태를 다시 정상(false)으로 돌린다. 그렇지 않으면 이후에도 계속 인터럽트가 발생하기 때문이다.
Reference
- 김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
'Language > Java' 카테고리의 다른 글
ExecutorService의 우아한 종료 (0) | 2024.10.21 |
---|---|
Executor 프레임워크(ExecutorService, Callable, Future) (0) | 2024.10.18 |
자바에서 자식 메서드가 부모 메서드가 던지는 체크 예외의 하위 타입만 던질 수 있는 이유 (0) | 2024.10.14 |
스레드의 생명주기 (0) | 2024.10.14 |
스레드 로컬(ThreadLocal) (0) | 2024.07.08 |