프로젝트를 진행하면서 Thread를 활용해야 하는 작업을 진행하고 있었다.
그러면서 특정 조건에서 Thread를 죽여야만 하는 상황이 존재했는데 어떻게 하면 외부에서 Thread를 죽일 수 있는지에 대해 고민하고 있었다.
Thread의 run 내부에서는 보통 while true를 활용해서 무한 루프를 돌기 마련인데 이걸 특정 Flag를 활용해서 while true 가 아니라 while !flag 와 같은 식으로 while 문을 돌면서 flag 를 검사해주는 방식으로 할 지에 대해 고민했다.
결국에는 외부에서 해당 Thread 내에 있는 boolean stop flag 변수에 접근해서 해당 변수의 값을 바꿔주었고 while로 무한 루프를 돌던 Thread는 해당 stop flag 값이 true가 되었음을 체크하고는 더 이상 while문을 돌지 않는 방식으로 구현했다.
그런데 해당 코드를 구현하면서 든 생각은 이 방법 말고 더 나은 방법이 있을 것이라고 생각했다. 분명 Java에서 지원해주는 방법이 있을 것이라고 생각했다.
그리고 찾아본 결과 interrupt 라는 것을 발견했다.
참고로 내가 구현한 코드와는 사실상 별 차이 없다. 다만 Java에서 지원해주는 방식이니 이 편이 좀 더 나을 것이라고 생각한다.
interrupt 방식은 interrupt() 라는 메서드를 활용한다. 그러면 해당 Thread 내의 run 에서는 while 루프의 조건에 아래처럼 명시한다.
!isInterrupted()
이를 체크하면서 돌던 while loop 은 interrupted 가 걸림을 체크하고는 loop를 빠져나가는 형태이다.
다른 메서드는 없을까?
있긴 하다.
Thread.destroy() 와 Thread.stop() 이 존재한다.
하지만 둘 다 권장되지 않는다고 한다. 그냥 쓰지 말라는 소리다.
참고로 destroy의 경우는 아예 구현이 되어 있지 않다고 한다. 사실 이 함수는 원래는 Thread를 파괴하기 위해서 만들어졌지만 이 함수를 구현하게 될 경우 리소스를 정리하지 못해서 데드락이 발생할 수 있기 때문에 구현되지 않았다고 한다.
Thread.stop() 함수도 비슷한 이유 때문에 권장되지 않는다고 한다. Java의 모든 객체들은 Monitor 를 가지고 있어서 하나의 객체를 여러 스레드에서 접근할 수 없도록 잠금 기능을 사용한다고 한다. 그런데 Thread.stop() 함수를 활용해서 스레드를 멈추게 될 경우 이 Monitor 잠금 기능이 풀려서 여러 스레드가 접근하게 되어 일관성이 깨지는 문제가 발생할 수 있다고 하낟.
그래서 권장되는 방식이 맨 처음에 언급한 Thread.interrupt() 함수인 것이다.
그렇다면 간단한 예제만 살펴보고 넘어가자.
예제는 두번째 블로그에 있는 예제를 참고했다.
잘 쓰겠습니다. 감사합니다.
아래에서 설명을 진행하겠다.
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
while (!Thread.currentThread().isInterrupted()) {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 공유자원 정리
// 해당 스레드에서 사용한 메모리 자원 정리
}
});
thread.start();
System.out.println(Thread.currentThread().getName());
Thread.sleep(2000);
thread.interrupt();
}
우선 Thread 를 하나 만들어주었다. 그런데 while 문의 조건을 보면 재밌는게 있다. isInterrupted가 보일 것이다. 이렇게 사용한다고 알면 된다.
finally 같은 경우는 socket 이던 BufferedReader이던 간에 관련된 close 작업 및 자원 정리를 진행하면 된다.
thread.interrupt() 처럼 interrupt 를 걸어서 확인할 수 있다.
그리고 지금 catch 절에서 InterruptedException 을 잡고 있는게 보일텐데 그냥 적어준게 아니라 이 부분이 꽤 중요한 부분이다.
interrupt() 는 사용하자마자 즉각 스레드가 중지되는 것이 아니다. interrupt() 는 일종의 요청이라고 보면 된다. 스레드가 실행 대기 혹은 실행 상태에 있을 때 interrupt() 메소드가 실행되면 즉시 InterruptedException 예외가 발생하지 않고 스레드가 미래에 일시 정지 상태가 되면 그때 InterruptedException 예외가 발생하는 것이다. 그래서 스레드가 일시 정기 상태가 되지 않으면 사실상 interrupt() 메소드 호출은 의미가 없다.
이 정도로 이해하면 될 것이다. interrupt() 는 요청이다.
아래 블로그에서 많은 도움을 받았다.
감사합니다.
https://jaeryo2357.tistory.com/97
https://sas-study.tistory.com/373
https://www.delftstack.com/ko/howto/java/kill-thread-java/
https://m.blog.naver.com/qbxlvnf11/221106055566
https://ict-nroo.tistory.com/22
'Java' 카테고리의 다른 글
[Java] Java의 참조 (0) | 2023.01.01 |
---|---|
[Java] ConcurrentModificationException 예외 해결 방법 (0) | 2022.12.08 |
[Java] 생성자에서는 getInstance호출에 신중하자. (0) | 2022.11.30 |
[Java] Java에서 Redis 를 사용해보자. Jedis 사용하기 (0) | 2022.11.23 |
[Java] PrintWriter 의 AutoFlush 사용 (0) | 2022.11.23 |