Java에서 스레드 인터럽트 (Thread Interrupt) 제대로 이해하기

JunSuPark·2025년 2월 12일
post-thumbnail

스레드 인터럽트란?

Java에서 interrupt() 메서드를 사용하면 Waiting, Timed_Waiting 상태의 스레드를 직접 깨워 Runnable 상태로 만들 수 있다. 하지만 interrupt()를 호출한다고 해서 즉시 InterruptedException이 발생하는 것은 아니다. 오직 sleep(), wait(), join() 같은 인터럽트 예외를 던지는 메서드를 호출하거나 호출 중일 때만 예외가 발생한다.

예제 코드로 살펴보는 인터럽트

아래 여러 버전의 코드를 통해 스레드를 중단하는 다양한 방법을 확인해 보자.


1. volatile 플래그를 사용한 방법 (ThreadStopMainV1)

static class MyTask implements Runnable {
    volatile boolean runFlag = true;

    @Override
    public void run() {
        while (runFlag) {
            log("작업중");
            sleep(3000);
        }
        log("자원 정리");
        log("작업 종료");
    }
}
  • volatile 변수를 사용하여 스레드가 false를 감지하면 반복문을 종료하도록 설계했다.
  • 하지만 이 방법은 sleep() 상태에서는 즉시 반응하지 않기 때문에 반응 속도가 느릴 수 있다.

2. interrupt()를 사용한 방법 (ThreadStopMainV2)

static class MyTask implements Runnable {
    @Override
    public void run() {
        try {
            while (true) {
                log("작업중");
                Thread.sleep(3000);
            }
        } catch (InterruptedException e) {
            log("인터럽트 발생: " + e.getMessage());
        }
        log("자원 정리");
        log("작업 종료");
    }
}
  • interrupt()를 사용하면 sleep()이 실행 중일 때 즉시 InterruptedException이 발생하여 종료된다.
  • 하지만 인터럽트 상태는 자동으로 초기화(false) 된다.

3. isInterrupted()를 사용한 방법 (ThreadStopMainV3)

static class MyTask implements Runnable {
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            log("작업중");
        }
        try {
            log("자원 정리 시도");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            log("자원 정리 실패 - 인터럽트 발생");
        }
        log("작업 종료");
    }
}
  • isInterrupted()단순히 인터럽트 상태를 확인하는 역할을 한다. (초기화 X)
  • 하지만 sleep() 호출 시 다시 InterruptedException이 발생하면, 한번 더 예외 처리가 필요하다.

4. Thread.interrupted()를 사용한 방법 (ThreadStopMainV4)

static class MyTask implements Runnable {
    @Override
    public void run() {
        while (!Thread.interrupted()) {
            log("작업중");
        }
        try {
            log("자원 정리 시도");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            log("자원 정리 실패 - 인터럽트 발생");
        }
        log("작업 종료");
    }
}
  • Thread.interrupted()현재 스레드의 인터럽트 상태를 확인한 후 초기화(false) 해준다.
  • 따라서 인터럽트 상태가 계속 유지되지 않고 한 번만 감지되어 정상적으로 종료된다.

인터럽트 상태 관리의 중요성

  1. interrupt()가 호출된다고 즉시 InterruptedException이 발생하는 것이 아니다.
  2. sleep(), wait(), join() 같은 메서드를 호출해야만 InterruptedException이 발생한다.
  3. 인터럽트 상태가 true라면, InterruptedException이 발생하면서 다시 false로 초기화된다.
  4. isInterrupted()는 단순 확인만 하고 초기화하지 않는다.
  5. Thread.interrupted()는 인터럽트 상태를 확인한 후 false로 초기화하여 연속적인 예외 발생을 방지한다.

결론

Java에서 스레드를 안전하게 중단하려면 interrupt()Thread.interrupted()를 적절히 활용해야 한다. 특히, 인터럽트 예외 발생 후 상태를 초기화하지 않으면 스레드가 계속 인터럽트 상태를 유지하여 예상치 못한 동작을 유발할 수 있다. 따라서 올바른 방식으로 인터럽트를 처리하여 리소스를 안전하게 정리하는 것이 중요하다.

이제 인터럽트를 제대로 이해하고, 올바르게 적용해 보자! 🚀

profile
배움을 추구하는 개발자

0개의 댓글