Thread interrupt

서버란·2024년 9월 19일

자바 궁금증

목록 보기
25/35

스레드에서 인터럽트(interrupt)는 스레드에게 특정한 작업을 중단하거나 변경할 필요가 있음을 알리는 신호입니다. 자바에서는 interrupt() 메서드를 사용해 스레드에 인터럽트 신호를 보낼 수 있습니다. 스레드가 인터럽트 상태가 되면, 이 상태를 확인하고 처리해야 합니다. 자바에서는 인터럽트 상태를 관리하기 위해 몇 가지 메서드가 제공됩니다: isInterrupted()interrupted()가 그 예입니다.

1. 인터럽트 상태란?

스레드에 인터럽트 신호가 보내지면, 해당 스레드는 인터럽트 상태가 true로 설정됩니다. 이 상태는 스레드가 특정 동작을 변경하거나 작업을 중단해야 할 때 유용합니다.

그러나 인터럽트 상태가 한 번 true로 설정되면, 이 상태를 적절하게 처리해야 합니다. 그렇지 않으면, 스레드가 계속해서 인터럽트 상태에 놓이게 되어 이후 작업이 중단되거나 비정상적인 동작을 초래할 수 있습니다.

2. isInterrupted()와 interrupted() 차이점

자바에서 스레드의 인터럽트 상태를 확인하거나 인터럽트 상태를 리셋하기 위해 두 가지 메서드가 제공됩니다: isInterrupted()와 interrupted().

1) isInterrupted()

  • isInterrupted()는 스레드의 인터럽트 상태를 확인하는 메서드입니다. 이 메서드를 호출하면, 현재 스레드의 인터럽트 상태가 true인지 false인지를 반환합니다.
  • 중요한 점은, 이 메서드를 호출해도 인터럽트 상태가 리셋되지 않습니다. 즉, 상태를 확인만 할 뿐, 스레드의 인터럽트 상태는 유지됩니다.

예시:

Thread thread = new Thread(() -> {
    while (!Thread.currentThread().isInterrupted()) {
        // 작업 수행
    }
});

위 코드에서 isInterrupted()는 스레드가 인터럽트 상태인지를 확인하고, true이면 루프를 중단하게 합니다. 이때, 인터럽트 상태는 그대로 유지됩니다.

2) interrupted()

  • interrupted()는 현재 스레드의 인터럽트 상태를 확인하고, 동시에 그 상태를 false로 리셋하는 메서드입니다.
  • 즉, 이 메서드를 호출하면 스레드의 인터럽트 상태가 true인지 false인지를 반환하면서, 인터럽트 상태를 자동으로 false로 재설정합니다.

예시:

Thread thread = new Thread(() -> {
    while (!Thread.interrupted()) {  // 상태 확인 후 리셋됨
        // 작업 수행
    }
});

위 코드에서 interrupted()는 스레드가 인터럽트 상태인지 확인한 후, 인터럽트 상태를 false로 리셋합니다. 이 메서드를 반복해서 호출하면 첫 번째 호출 후에는 항상 false가 반환됩니다.

3. 인터럽트 상태를 다시 false로 리셋하는 이유

인터럽트가 발생했을 때, 인터럽트 상태를 확인한 후 다시 false로 리셋하지 않으면, 스레드가 계속해서 인터럽트 상태로 유지되게 됩니다. 이것은 의도하지 않은 작업 중단이나 예외 발생을 초래할 수 있습니다.

예시: 인터럽트 상태를 리셋하지 않는 경우

Thread thread = new Thread(() -> {
    try {
        Thread.sleep(10000);  // 10초 동안 잠자기
    } catch (InterruptedException e) {
        // InterruptedException 발생 시 인터럽트 상태가 자동으로 리셋됨
        System.out.println("인터럽트 발생");
    }
});

thread.start();
thread.interrupt();  // 스레드에 인터럽트 신호
  • 여기서, sleep() 메서드는 InterruptedException을 발생시킵니다. 이 예외가 발생하면, 스레드의 인터럽트 상태는 자동으로 false로 리셋됩니다. 만약, 예외가 발생하지 않는 다른 경우에도 스레드의 상태를 계속 유지하려면 직접 상태를 확인하고 처리해야 합니다.

따라서, 인터럽트 상태를 다시 false로 돌리는 이유는 스레드가 의도하지 않게 이후에도 계속 인터럽트 상태를 유지하지 않도록 하기 위해서입니다. 인터럽트 상태가 계속 true로 유지되면, 스레드가 이후 실행 중인 다른 작업에서도 계속 방해를 받을 수 있습니다.

4. InterruptedException과 인터럽트 상태

InterruptedException은 스레드가 대기, 슬립, 조인 등의 작업을 수행하는 중에 인터럽트가 발생하면 던져지는 예외입니다. 이 예외가 발생하면, 인터럽트 상태가 자동으로 false로 리셋됩니다. 이 때문에, InterruptedException이 발생한 후에는 다시 인터럽트 상태를 설정해 주어야 할 때도 있습니다.

예시:

Thread thread = new Thread(() -> {
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        // 인터럽트가 발생하면 예외 처리 후 상태 리셋
        Thread.currentThread().interrupt();  // 상태를 다시 true로 설정
    }
});

위 코드에서는 InterruptedException 발생 후 상태가 리셋되지만, 다시 interrupt()를 호출하여 상태를 true로 재설정하고 있습니다. 이를 통해 이후에 스레드가 적절하게 인터럽트 상태를 반영할 수 있게 됩니다.

5. 요약

  • isInterrupted(): 현재 스레드의 인터럽트 상태를 확인하지만, 상태를 리셋하지 않습니다. 상태가 true이면, 그 상태는 유지됩니다.
  • interrupted(): 현재 스레드의 인터럽트 상태를 확인하고, 동시에 상태를 false로 리셋합니다. 상태를 다시 false로 돌려주기 때문에, 이후 호출에서는 false가 반환됩니다.
  • 인터럽트 상태 리셋의 이유: 스레드가 계속해서 인터럽트 상태로 남아 있는 것을 방지하기 위함입니다. 그렇지 않으면, 이후 작업에서 계속 인터럽트 신호를 받아서 작업이 방해될 수 있습니다.
  • InterruptedException 발생 시 인터럽트 상태는 자동으로 리셋되며, 필요에 따라 다시 상태를 설정해야 할 수도 있습니다.

Q1. 인터럽트 상태를 확인한 후 상태를 리셋하지 않으면 어떤 문제가 발생할 수 있나요?

인터럽트 상태를 확인한 후 상태를 리셋하지 않으면, 스레드는 계속해서 인터럽트 상태로 남아 있게 됩니다. 이로 인해 스레드가 수행하는 작업이 지속적으로 방해될 수 있습니다.

구체적인 문제:

  • 스레드가 재작업을 계속 방해받을 수 있음: 인터럽트 상태가 유지된 채로 스레드가 실행되면, 이후에 실행되는 다른 메서드나 작업들도 인터럽트 상태를 인식하고 중단되거나 방해받을 수 있습니다. 예를 들어, 스레드가 반복적으로 대기, 슬립, 조인과 같은 작업을 수행할 때마다 InterruptedException이 발생할 수 있습니다.

  • 정상적인 실행 흐름 방해: 인터럽트 상태가 리셋되지 않으면, 스레드는 다른 코드에서 예상치 못한 동작을 할 수 있습니다. 특히 대기 상태에서 깨어나는 동작이 여러 번 일어날 수 있습니다.

따라서 인터럽트가 한 번 처리되면, 그 상태를 적절히 리셋하여 스레드가 다시 정상적인 상태로 돌아가게 해야 합니다.

Q2. InterruptedException이 발생하면 스레드의 인터럽트 상태가 왜 자동으로 false로 리셋되나요?

InterruptedException은 스레드가 대기, 슬립, 조인과 같은 작업 중에 인터럽트가 발생하면 던져지는 예외입니다. 이 예외가 발생하면, 자바는 스레드의 인터럽트 상태를 자동으로 false로 리셋합니다. 그 이유는 인터럽트 신호를 한 번 처리한 후 스레드가 더 이상 중단되지 않고, 다시 정상 상태로 돌아가도록 보장하기 위해서입니다.

자동 리셋의 이유:

  • 한 번 인터럽트를 처리하면 상태를 초기화하여 스레드가 계속해서 중단되지 않도록 하기 위해: InterruptedException이 발생했을 때, 스레드가 인터럽트 신호를 처리하고 나면, 해당 상태를 다시 false로 리셋하여 스레드가 정상적으로 작업을 재개할 수 있도록 합니다. 만약 상태를 리셋하지 않으면, 스레드는 계속해서 인터럽트 신호를 받는 상태로 남아있어 중단되거나 예외가 발생할 가능성이 높습니다.

예시:

try {
    Thread.sleep(10000);  // 스레드가 슬립 상태로 진입
} catch (InterruptedException e) {
    // InterruptedException이 발생하면 인터럽트 상태가 자동으로 false로 리셋됨
    System.out.println("인터럽트 발생");
}

여기서 Thread.sleep() 메서드가 인터럽트되면, InterruptedException이 발생하고 인터럽트 상태는 자동으로 리셋됩니다. 이렇게 하여 스레드는 인터럽트 신호를 한 번 처리한 후 정상적인 흐름을 계속 유지할 수 있습니다.

Q3. isInterrupted()와 interrupted() 메서드를 어떻게 적절히 사용할 수 있을까요?

isInterrupted()interrupted()는 각각의 용도에 맞게 사용하는 것이 중요합니다. 각 메서드는 스레드의 인터럽트 상태를 확인하거나 상태를 리셋하는 데 사용됩니다.

1) isInterrupted()의 적절한 사용

  • 인터럽트 상태를 확인만 하고 싶을 때: 스레드의 인터럽트 상태를 확인하고 싶지만, 인터럽트 상태를 그대로 유지하고 싶은 경우 isInterrupted()를 사용합니다.

사용 예:

Thread thread = new Thread(() -> {
    while (!Thread.currentThread().isInterrupted()) {
        // 스레드가 인터럽트되지 않았을 때 계속 실행
    }
});

이 예시에서 isInterrupted()는 현재 스레드의 상태를 확인하기만 할 뿐, 상태를 리셋하지 않습니다. 스레드가 인터럽트 상태를 유지하면서 특정 작업을 계속 수행할 수 있습니다.

2) interrupted()의 적절한 사용

  • 인터럽트 상태를 확인하고, 동시에 상태를 리셋하고 싶을 때 사용합니다. 스레드의 인터럽트 신호를 확인한 후, 상태를 초기화하여 정상적인 흐름으로 돌아가도록 할 때 유용합니다.

사용 예:

Thread thread = new Thread(() -> {
    while (!Thread.interrupted()) {  // 상태를 확인하고 동시에 리셋
        // 스레드가 인터럽트되지 않았을 때 계속 실행
    }
});

이 코드에서 interrupted()는 인터럽트 상태를 확인한 후 자동으로 상태를 false로 리셋하여, 한 번 인터럽트 신호를 처리한 후 스레드가 다시 정상적으로 작업을 이어갈 수 있게 합니다.

요약:

  • isInterrupted()는 상태를 확인하고 상태를 유지할 때 사용합니다.
  • interrupted()는 상태를 확인하면서 동시에 리셋하여 정상적인 작업 흐름을 복구할 때 사용합니다.
profile
백엔드에서 서버엔지니어가 된 사람

0개의 댓글