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
volatile 키워드는 뒤에서 자세히 설명한다. 지금은 단순히 여러 스레드에서 공유하는 값에 사용하는 키워드
라고 알아두자.
실행 결과
14:58:27.520 [ work] 작업 중
14:58:30.525 [ work] 작업 중
14:58:31.510 [ main] 작업 중단 지시 runFlag=false
14:58:33.532 [ work] 자원 정리
14:58:33.533 [ work] 작업 종료
work 스레드는 runFlag 가 true 인 동안 계속 실행된다.
프로그램 시작 후 4초 뒤에 main 스레드는 runFlag를 false 로 변경한다.
work 스레드는 while(runFlag) 에서 runFlag 의 조건이 false 로 변한 것을 확인하고, while문을 빠져 나가면서 작업을 종료한다.
문제점
실행을 해보면 알겠지만 main 스레드가 runFlag=false 를 통해 작업 중단을 지시해도, work 스레드가 즉각 반응하지 않는다. 로그를 보면 작업 중단 지시 2초 정도 이후에 자원을 정리하고 작업을 종료한다.
14:58:27.520 [ work] 작업 중
14:58:30.525 [ work] 작업 중
14:58:31.510 [ main] 작업 중단 지시 runFlag=false
14:58:33.532 [ work] 자원 정리 //2초 정도 경과후 실행
14:58:33.533 [ work] 작업 종료
Thread.currentThread() 로 이 코드를 실행하는 스레드를 조회할 수 있다.
isInterrupted() 를 사용하면 스레드가 인터럽트 상태인지 확인할 수 있다.
실행 결과
...
18:32:05.247 [ work] 작업 중
18:32:05.247 [ work] 작업 중
18:32:05.247 [ main] 작업 중단 지시 - thread.interrupt()
18:32:05.247 [ work] 작업 중
18:32:05.250 [ main] work 스레드 인터럽트 상태1 = true
18:32:05.250 [ work] work 스레드 인터럽트 상태2 = true
18:32:05.251 [ work] 자원 정리 시도
18:32:05.251 [ work] 자원 정리 실패 - 자원 정리 중 인터럽트 발생
18:32:05.251 [ work] work 스레드 인터럽트 상태3 = false
18:32:05.251 [ work] 작업 종료
반복문으로 작업 중을 계속 출력하기 때문에 상당히 많은 작업 중 로그가 출력된다.
주요 실행 순서
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 )으로 돌아온다.
work 스레드 인터럽트 상태3 = false
그럼 우리는 어떻게 해야할까?
while(인터럽트_상태_확인) 같은 곳에서 인터럽트의 상태를 확인한 다음에, 만약 인터럽트 상태( true )라면 인터럽트 상태를 다시 정상( false )으로 돌려두면 된다.
인터럽트 - 시작4
Thread.interrupted()
스레드의 인터럽트 상태를 단순히 확인만 하는 용도라면 isInterrupted() 를 사용하면 된다. 하지만 직접 체크해서 사용할 때는 Thread.interrupted() 를 사용해야 한다.
이 메서드는 다음과 같이 작동한다.
스레드가 인터럽트 상태라면 true 를 반환하고, 해당 스레드의 인터럽트 상태를 false 로 변경한다.
스레드가 인터럽트 상태가 아니라면 false 를 반환하고, 해당 스레드의 인터럽트 상태를 변경하지 않는다.
...
18:42:18.214 [ work] 작업 중
18:42:18.214 [ work] 작업 중
18:42:18.214 [ main] 작업 중단 지시 - thread.interrupt()
18:42:18.214 [ work] 작업 중
18:42:18.219 [ main] work 스레드 인터럽트 상태1 = true
18:42:18.219 [ work] work 스레드 인터럽트 상태2 = false
18:42:18.219 [ work] 자원 정리 시도
18:42:19.221 [ work] 자원 정리 완료
18:42:19.222 [ work] 작업 종료
주요 코드
while (!Thread.interrupted()) { //인터럽트 상태 변경Olog("작업 중");
}
주요 실행 순서
main 스레드는 interrupt() 메서드를 사용해서, work 스레드에 인터럽트를 건다.
work 스레드는 인터럽트 상태이다. Thread.interrupted() 의 결과는 true 가 된다.
Thread.interrupted() 는 이때 work 스레드의 인터럽트 상태를 정상( false )으로 변경한다.
이때 다음과 같이 while 조건이 false 가 되면서 while문을 탈출한다.
while (!Thread.interrupted())
while (!true)
while (false)
Thread.interrupted() 를 호출했을 때 스레드가 인터럽트 상태( true )라면, true 를 반환하고, 해당 스레드의
인터럽트 상태를 false 로 변경한다.
결과적으로 while문을 탈출하는 시점에, 스레드의 인터럽트 상태도 false 로 변경된다.
work 스레드는 이후에 자원을 정리하는 코드를 실행하는데, 이때 인터럽트의 상태는 false 이므로 인터럽트가 발생하는 sleep() 과 같은 코드를 수행해도 인터럽트가 발생하지 않는다. 이후에 자원을 정상적으로 잘 정리하는 것을 확인할 수 있다.
자바는 인터럽트 예외가 한 번 발생하면, 스레드의 인터럽트 상태를 다시 정상( false )으로 돌린다. 스레드의 인터럽트 상태를 정상으로 돌리지 않으면 이후에도 계속 인터럽트가 발생하게 된다. 인터럽트의 목적을 달성하면 인터럽트 상태를 다시 정상으로 돌려두어야 한다.
인터럽트의 상태를 직접 체크해서 사용하는 경우 Thread.interrupted() 를 사용하면 이런 부분이 해결된다. 참고
로 isInterrupted() 는 특정 스레드의 상태를 변경하지 않고 확인할 때 사용한다.
물론 꼭 이것만이 정답은 아니다. 예를 들어 너무 긴급한 상황이어서 자원 정리도 하지 않고, 최대한 빨리 스레드를 종료해야 한다면 해당 스레드를 다시 인터럽트 상태로 변경하는 것도 방법이다.
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.
인터럽트 - 시작1
라고 알아두자.
실행 결과
문제점
실행을 해보면 알겠지만 main 스레드가 runFlag=false 를 통해 작업 중단을 지시해도, work 스레드가 즉각 반응하지 않는다. 로그를 보면 작업 중단 지시 2초 정도 이후에 자원을 정리하고 작업을 종료한다.
이 방식의 가장 큰 문제는 다음 코드의 sleep() 에 있다.
어떻게 하면 sleep() 처럼 스레드가 대기하는 상태에서 스레드를 깨우고, 작업도 빨리 종료할 수 있을까?
인터럽트 - 시작2
기중일 때 예외가 발생한다.
실행 결과
있다.
가 발생한다.
또는 이미 호출하고 대기 중이라면 InterruptedException 이 발생한다.
스레드의 인터럽트 상태는 종료된다.
주요 로그
runFlag 를 사용하는 이전 방식보다 반응성이 좋아진 것을 확인할 수 있다.
인터럽트 - 시작3
실행 결과
주요 실행 순서
main 스레드는 interrupt() 메서드를 사용해서, work 스레드에 인터럽트를 건다.
work 스레드는 인터럽트 상태이다. isInterrupted()=true 가 된다.
이때 다음과 같이 while 조건이 false 가 되면서 while문을 탈출한다.
여기까지 보면 아무런 문제가 없어 보인다. 하지만 이 코드에는 심각한 문제가 있다. 바로 work 스레드의 인터럽트 상태가 true 로 계속 유지된다는 점이다. 앞서 인터럽트 예외가 터진 경우 스레드의 인터럽트 상태는 false 가 된다. 반면에 isInterrupted() 메서드는 인터럽트의 상태를 변경하지 않는다. 단순히 인터럽트의 상태를 확인만 한다.
work 스레드는 이후에 자원을 정리하는 코드를 실행하는데, 이때도 인터럽트의 상태는 계속 true 로 유지된다. 이때 만약 인터럽트가 발생하는 sleep() 과 같은 코드를 수행한다면, 해당 코드에서 인터럽트 예외가 발생하게 된다.
이것은 우리가 기대한 결과가 아니다! 우리가 기대하는 것은 while() 문을 탈출하기 위해 딱 한 번만 인터럽트를 사용 하는 것이지, 다른 곳에서도 계속해서 인터럽트가 발생하는 것이 아니다.
결과적으로 자원 정리를 하는 도중에 인터럽트가 발생해서, 자원 정리에 실패한다. 자바에서 인터럽트 예외가 한 번 발생하면, 스레드의 인터럽트 상태를 다시 정상( false )으로 돌리는 것은 이런 이유 때문이다.
스레드의 인터럽트 상태를 정상으로 돌리지 않으면 이후에도 계속 인터럽트가 발생하게 된다. 인터럽트의 목적을 달성하면 인터럽트 상태를 다시 정상으로 돌려두어야 한다.
참고로 이 예제에서 자원 정리에 실패할 때 인터럽트 예외가 발생하면서 인터럽트의 상태가 정상( false )으로 돌아온다.
그럼 우리는 어떻게 해야할까?
while(인터럽트_상태_확인) 같은 곳에서 인터럽트의 상태를 확인한 다음에, 만약 인터럽트 상태( true )라면 인터럽트 상태를 다시 정상( false )으로 돌려두면 된다.
인터럽트 - 시작4
Thread.interrupted()
실행 결과
주요 코드
주요 실행 순서
Thread.interrupted() 를 호출했을 때 스레드가 인터럽트 상태( true )라면, true 를 반환하고, 해당 스레드의
인터럽트 상태를 false 로 변경한다.
결과적으로 while문을 탈출하는 시점에, 스레드의 인터럽트 상태도 false 로 변경된다.
work 스레드는 이후에 자원을 정리하는 코드를 실행하는데, 이때 인터럽트의 상태는 false 이므로 인터럽트가 발생하는 sleep() 과 같은 코드를 수행해도 인터럽트가 발생하지 않는다. 이후에 자원을 정상적으로 잘 정리하는 것을 확인할 수 있다.
자바는 인터럽트 예외가 한 번 발생하면, 스레드의 인터럽트 상태를 다시 정상( false )으로 돌린다. 스레드의 인터럽트 상태를 정상으로 돌리지 않으면 이후에도 계속 인터럽트가 발생하게 된다. 인터럽트의 목적을 달성하면 인터럽트 상태를 다시 정상으로 돌려두어야 한다.
인터럽트의 상태를 직접 체크해서 사용하는 경우 Thread.interrupted() 를 사용하면 이런 부분이 해결된다. 참고
로 isInterrupted() 는 특정 스레드의 상태를 변경하지 않고 확인할 때 사용한다.
물론 꼭 이것만이 정답은 아니다. 예를 들어 너무 긴급한 상황이어서 자원 정리도 하지 않고, 최대한 빨리 스레드를 종료해야 한다면 해당 스레드를 다시 인터럽트 상태로 변경하는 것도 방법이다.
All reactions