You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Thread.currentThread() 로 이 코드를 실행하는 스레드를 조회할 수 있다.
isInterrupted() 를 사용하면 스레드가 인터럽트 상태인지 확인할 수 있다.
실행 결과
반복문으로 작업을 계속 출력하기 때문에 상당히 많은 작업 중 로그가 출력된다.
실행 결과는 이해하기 쉽게 조정했다.
주요 실행 순서
main 스레드는 interrupt() 메서드를 사용해서, work 스레드에 인터럽트를 건다.
work 스레드는 인터럽트 상태이다. isInterrupted() = true가 된다.
이때 다음과 같이 while 조건이 false가 되면서 while을 탈출한다.
while (!Thread.currentThread().isInterrupted())
while (!true)
while (false)
여기까지 아무런 문제가 없어 보인다. 하지만 이 코드에는 심각한 문제가 있다.
바로 work 스레드의 인터럽트 상태가 true 로 계속 유지된다는 점이다.
앞서 인터럽트 예외가 터진 경우 스레드의 인터럽트 상태는 false가 된다.
반면에 isInterrupted() 메서드는 인터럽트의 상태를 변경하지 않는다. 단순히 인터럽트의 상태를 확인만 한다.
work 스레드는 이후에 자원을 정리하는 코드를 실행하는데, 이때도 인터럽트의 상태는 계속 true로 유지된다. 이때 만약 인터럽트가 발생할 수 있는 sleep()과 같은 코드를 수행한다면, 해당 코드에서 인터럽트 예외가 발생하게 된다. 이것은 우리가 기대한 결과가 아니다! 우리가 기대하는 것은 while()을 탈출하기 위해 딱 한 번만 인터럽트를 사용하는 것이지, 다른 곳에서도 계속해서 인터럽트가 발생하는 것이 아니다.
결과적으로 자원 정리를 하는 도중에 인터럽트가 발생해서, 자원 정리에 실패한다. 자바에서 인터럽트 예외가 한 번 발생하면, 스레드의 인터럽트 상태를 다시 정상(false)으로 돌리는 것은 이런 이유때문이다.
스레드의 인터럽트 상태를 정상으로 돌리지 않으면 이후에도 계속 인터럽트가 발생하게 된다.
인터럽트의 목적을 달성하면 인터럽트 상태를 다시 정상으로 돌려두어야 한다.
참고로 이 예제에서 자원 정리에 실패할 때 인터럽트 예외가 발생하면서 인터럽트의 상태가 정상(false)으로 돌아온다.
그럼 우리는 어떻게 해야할까? while(인터럽트_상태_확인) 같은 곳에서 인터럽트의 상태를 확인한 다음, 만약 인터럽트 상태 (true)라면 인터럽트 상태를 다시 정상 (false)으로 돌려두면 된다.
1.4. 인터럽트 - 시작 4
Thread.interrupted()
스레드의 인터럽트 상태를 단순히 확인만 하는 용도라면 isInterrupted()를 사용하면 된다.
하지만 직접 체크해서 사용할 때는 Thread.interrupted()를 사용해야 한다.
이 메서드는 다음과 같이 작동한다.
스레드가 인터럽트 상태라면 true를 반환하고, 해당 스레드의 인터럽트 상태를 false로 변경한다.
스레드가 인터럽트 상태가 아니라면 false를 반환하고, 해당 스레드의 인터럽트 상태를 변경하지 않는다.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
0x01. 인터럽트
1.1. 인터럽트 - 시작 1
특정 스레드의 작업을 중간에 중단하려면 어떻게 해야할까?
다음 코드를 보자.
runFlag를 사용해서work스레드에 작업 중단을 지시할 수 있다.sleep(3000)을 사용하자.main스레드는 4초 뒤에 작업 중단을 지시한다.실행 결과
work스레드는runFlag가true인 동안 계속 실행된다.main스레드는runFlag를false로 변경한다.work스레드는while(runFlag)에서runFlag의 조건이false로 변한 것을 확인하고, while문을 빠져나가면서 작업을 종료한다.문제점
실행을 해보면 알겠지만
main스레드가runFlag=false를 통해 작업 중단을 지시해도,work스레드가 즉각 반응하지는 않는다. 로그를 보면 작업 중단 지시 2초 정도 이후에 자원을 정리하고 작업을 종료한다.이 방식의 가장 큰 문제는 다음 코드의
sleep()에 있다.main스레드가runFlag를false로 변경해도,work스레드는sleep(3000)을 통해 3초간 잠들어 있을 수 있다. 3초간의 잠이 깬 다음에while(runFlag)코드를 실행해야,runFlag를 확인하고 작업을 중단할 수 있다.runFlag를 변경한 후 2초라는 시간이 지난 이후에 작업이 종료되는 이유는work스레드가 3초에 한번씩 깨어나서runFlag를 확인하는데,main스레드가 4초에runFlag를 변경했기 때문이다.work스레드 입장에서 보면 두 번째sleep()에 들어가고 1초 후main스레드가runFlag를 변경한다. 3초간sleep()이므로 아직 2초가 더 있어야 깨어난다.어떻게 하면
sleep()처럼 스레드가 대기하는 상태에서 스레드를 깨우고, 작업도 빨리 종료할 수 있을까?1.2. 인터럽트 - 시작 2
예를 들어서, 특정 스레드가
Thread.sleep()을 통해 쉬고 있는데, 처리해야 하는 작업이 들어와서 해당 스레드를 급하게 깨워야 할 수 있다. 또는sleep()으로 쉬고 있는 스레드에게 더는 일이 없으니, 작업 종료를 지시할 수도 있다.인터럽트를 사용하면,
WAITING,TIMED_WAITING같은 대기 상태의 스레드를 직접 깨워서, 작동하는RUNNABLE상태로 만들 수 있다.앞서 작성한 예제의 작업 중단 지시를 인터럽트를 통해 처리해보자.
run()에서는 인터럽트를 이해하기 위해, 직접 만든sleep()대신에Thread.sleep()을 사용하고,try ~ catch도 사용하자.interrupt()메서드를 호출하면, 해당 스레드에 인터럽트가 발생한다.InterruptedException이 발생한다.RUNNABLE상태가 되고, 코드를 정상 수행한다.InterruptedException을catch로 잡아서 정상 흐름으로 변경하면 된다.interrupt()를 호출했다고 즉각InterruptedException이 발생하는 것은 아니다. 오직sleep()처럼InterruptedException을 던지는 메서드를 호출하거나 또는 호출 중일 때 예외가 발생한다.while(true),log("작업 중")에서는InterruptedException이 발생하지 않는다.Thread.sleep()처럼InterruptedException을 던지는 메서드를 호출하거나 또는 호출하며 대기 중일 때 예외가 발생한다.실행 결과
thread.interrupt()를 통해 작업 중단을 지시를 하고, 거의 즉각적으로 인터럽트가 발생한 것을 확인할 수 있다.work스레드는TIMED_WAITING→RUNNABLE상태로 변경되면서InterruptedException예외가 발생한다.RUNNABLE상태여야catch의 예외 코드도 실행될 수 있다.work스레드가catch블록 안에서RUNNABLE상태로 바뀐 것을 확인할 수 있다.main스레드가 4초 뒤에work스레드에interrupt()를 건다.work스레드는 인터럽트 상태(true)가 된다.sleep()처럼InterruptedException이 발생하는 메서드를 호출하거나 또는 이미 호출하고 대기 중이라면InterruptedException이 발생한다.work스레드는TIMED_WAITING상태에서RUNNABLE상태로 변경되고,InterruptedException예외를 처리하면서 반복문을 탈출한다.work스레드는 인터럽트 상태가 되었고, 인터럽트 상태이기 때문에 인터럽트 예외가 발생한다.work스레드는 다시 작동하는 상태가 된다. 따라서work스레드의 인터럽트 상태는 종료된다.work스레드의 인터럽트 상태는false로 변경된다.주요 로그
runFlag를 사용하는 이전 방식보다 반응성이 좋아진 것을 확인할 수 있다.1.3. 인터럽트 - 시작 3
그런데 앞선 코드에서 한가지 아쉬운 부분이 있다.
여기서
while(true)부분은 체크를 하지 않는다는 점이다. 인터럽트가 발생해도 이 부분이 항상true이기 때문에 다음 코드로 넘어간다. 그리고sleep()을 호출하고 나서야 인터럽트가 발생하는 것이다.다음과 같이 인터럽트의 상태를 확인하면, 더 빨리 반응할 수 있을 것이다.
이 코드와 같이 인터럽트의 상태를 확인하면
while문을 체크하는 부분에서 더 빠르게while문을 빠져나갈 수 있다. 물론 이 예제의 경우 코드가 단순해서 실질적인 차이는 매우 작다.추가로 인터럽트의 상태를 직접 확인하면, 다음과 같이 인터럽트를 발생시키는
sleep()과 같은 코드가 없어도 인터럽트 상태를 직접 확인하기 때문에while문을 빠져나갈 수 있다.while문에서 인터럽트의 상태를 직접 확인하도록 코드를 변경해보자.추가로 예제를 단순화하고 더 직접적인 이해를 돕기 위해
run()의 반복문에서sleep()코드도 함께 제거하자.Thread.currentThread()로 이 코드를 실행하는 스레드를 조회할 수 있다.isInterrupted()를 사용하면 스레드가 인터럽트 상태인지 확인할 수 있다.실행 결과
주요 실행 순서
main스레드는interrupt()메서드를 사용해서,work스레드에 인터럽트를 건다.work스레드는 인터럽트 상태이다.isInterrupted() = true가 된다.while조건이false가 되면서while을 탈출한다.while (!Thread.currentThread().isInterrupted())while (!true)while (false)여기까지 아무런 문제가 없어 보인다. 하지만 이 코드에는 심각한 문제가 있다.
바로
work스레드의 인터럽트 상태가true로 계속 유지된다는 점이다.앞서 인터럽트 예외가 터진 경우 스레드의 인터럽트 상태는
false가 된다.반면에
isInterrupted()메서드는 인터럽트의 상태를 변경하지 않는다. 단순히 인터럽트의 상태를 확인만 한다.work스레드는 이후에 자원을 정리하는 코드를 실행하는데, 이때도 인터럽트의 상태는 계속true로 유지된다. 이때 만약 인터럽트가 발생할 수 있는sleep()과 같은 코드를 수행한다면, 해당 코드에서 인터럽트 예외가 발생하게 된다. 이것은 우리가 기대한 결과가 아니다! 우리가 기대하는 것은while()을 탈출하기 위해 딱 한 번만 인터럽트를 사용하는 것이지, 다른 곳에서도 계속해서 인터럽트가 발생하는 것이 아니다.결과적으로 자원 정리를 하는 도중에 인터럽트가 발생해서, 자원 정리에 실패한다.
자바에서 인터럽트 예외가 한 번 발생하면, 스레드의 인터럽트 상태를 다시 정상(
false)으로 돌리는 것은 이런 이유 때문이다.스레드의 인터럽트 상태를 정상으로 돌리지 않으면 이후에도 계속 인터럽트가 발생하게 된다.
인터럽트의 목적을 달성하면 인터럽트 상태를 다시 정상으로 돌려두어야 한다.
참고로 이 예제에서 자원 정리에 실패할 때 인터럽트 예외가 발생하면서 인터럽트의 상태가 정상(
false)으로 돌아온다.그럼 우리는 어떻게 해야할까?
while(인터럽트_상태_확인)같은 곳에서 인터럽트의 상태를 확인한 다음, 만약 인터럽트 상태 (true)라면 인터럽트 상태를 다시 정상 (false)으로 돌려두면 된다.1.4. 인터럽트 - 시작 4
Thread.interrupted()스레드의 인터럽트 상태를 단순히 확인만 하는 용도라면
isInterrupted()를 사용하면 된다.하지만 직접 체크해서 사용할 때는
Thread.interrupted()를 사용해야 한다.이 메서드는 다음과 같이 작동한다.
true를 반환하고, 해당 스레드의 인터럽트 상태를false로 변경한다.false를 반환하고, 해당 스레드의 인터럽트 상태를 변경하지 않는다.실행 결과
주요 코드
주요 실행 순서
ain스레드는interrupt()메서드를 사용해서,work스레드에 인터럽트를 건다.work스레드는 인터럽트 상태이다.Thread.interrupted()의 결과는true가 된다.Thread.interrupted()는 이때work스레드의 인터럽트 상태를 정상(false)으로 변경한다.while조건이false가 되면서while문을 탈출한다.while (!Thread.interrupted())while (!true)while (false)Thread.interrupted()를 호출했을 때 스레드가 인터럽트 상태라면,true를 반환하고, 해당 스레드의 인터럽트 상태를false로 변경한다.결과적으로
while문을 탈출하는 시점에, 스레드의 인터럽트 상태도false로 변경된다.work스레드는 이후에 자원을 정리하는 코드를 실행하는데, 이때 인터럽트의 상태는false이므로 인터럽트가 발생하는sleep()과 같은 코드를 수행해도 인터럽트가 발생하지 않는다. 이후에 자원을 정상적으로 잘 정리하는 것을 확인할 수 있다.자바는 인터럽트 예외가 한 번 발생하면, 스레드의 인터럽트 상태를 다시 정상(
false)으로 돌린다.스레드의 인터럽트 상태를 정상으로 돌리지 않으면 이후에도 계속 인터럽트가 발생하게 된다.
인터럽트의 목적을 달성하면 인터럽트 상태를 다시 정상으로 돌려두어야 한다.
인터럽트의 상태를 직접 체크해서 사용하는 경우
Thread.interrupted()를 사용하면 이런 부분이 해결된다. 참고로isInterrupted()는 특정 스레드의 상태를 변경하지 않고 확인할 때 사용한다.물론 꼭 이것만이 정답은 아니다. 예를 들어 너무 긴급한 상황이어서 자원 정리도 하지 않고, 최대한 빨리 스레드를 종료해야 한다면 해당 스레드를 다시 인터럽트 상태로 변경하는 것도 방법이다.
All reactions