문제점 #1: 

 

Thread.stop 메소드는 deprecated 되어버렸다.

 

안전하지 않다는 이유에서다.[1]

 

종료시키고자 하는 쓰레드가 Thread.stop을 통해 종료되게 되면 보유하고 있던 모니터들(monitors)을 전부 놓아(unlock)버리게 되는데, 이들에 의해 보호받고 있던 오브젝트들이 더이상 보호를 받지 못해 문제가 발생한다.  해당 오브젝트들이 일관적이지 않은 상태가 되면 보통 데미지를 받은(damaged) 상태라고 하는데 이 상태에서는 예상치 못한 결과가 나올 수 있다.  감지하기도 쉽지 않다. :(

 

심지어 ThreadDeath(?)는 쓰레드를 암살(?)해버려서 어떠한 경고도 사용자에게 주지 않는다.

 

해결책 #1: 

구글을 뒤져보니 다음과 같은 방법이 있었다.[2]

쓰레드 종료를 원할 때 특정 시나리오(주기적으로 같은 것을 실행하는 쓰레드)에서 변수 하나를 주어 계속 감지하는 것이다.  일단 진행하고자 했던 코드는 이 시나리오에 해당되기에 무사히 넘어갈 수 있었다.

 

public class AlarmRunnable implements Runnable {

    private volatile boolean running = true;

 

    public void terminate() {

        running = false;

    }

 

    @override

    public void run() {

        while(running) {

            try {

                Thread.sleep((long) 10000);

            } catch (InterruptedException e) {

                running = false;

            }

        }

    }

}

 

위 코드를 살펴보면 사용자가 원할 때 terminate() 메소드를 호출할 경우 running값이 false가 되어 run()메소드 내부의 반복문 while이 종료될 것이다.

또한, 원치 않는 exception이 발생했을 때도 마찬가지로 running값이 false가 되서 종료된다.

 

이제 이를 적용시키는 클래스 예를 들면

public class HelloThread {

    private Thread alarmThread = null;

    private AlarmRunnable alarmRunnable= null;

 

    public void alarmInitiate() {

        alarmRunnable = new AlarmRunnable();

        alarmThread = new Thread(alarmRunnable);

        alarmThread.start();

    }

 

    public void alarmTerminate() {

        if (alarmThread != null) {

            alarmRunnable.terminate();

            alarmThread.join();

        }

    }

}

 

대략 이런 느낌이다.

 

만약에 위의 코드처럼 10초마다 running 변수를 감지할 수 있는 형태가 아닌 시나리오라면 어떨까?

 

위의 방법을 쓰면 10초 주기로 running 변수를 확인해야하는 부분 때문에 CPU 사이클을 낭비하게 된다.

주기를 10초보다 짧게 주면 더 많은 CPU 사이클의 낭비를, 길게 주면 종료 처리까지 기다리는 시간이 길어진다.

따라서 다음과 같은 방법을 또 찾게 되었다.[3]

 

해결책 #2:  

Thread.interrupt() 메소드를 쓰면 InterruptedException이 발생되어 익셉션 처리 코드로 넘어가게 된다.

이 익셉션을 이용하여 쓰레드 종료에 필요한 정리를 하는 것이다.

참고로 InterruptedException을 발생시키는 것은

interrupt() 호출 시점에 Object 클래스의 wait(), wait(long), wait(long, int)나 

Thread 클래스의 join(), join(long), join(long, int), sleep(long), sleep(long, int)메소드가 호출될 경우이다. [3]

 

 다음은 run() 메소드를 오버라이드하여 InterruptedException이 감지되었을 때 쓰레드를 종료시키도록 유도하는 코드의 예이다.  alarmRunnable과 alarmThread는 스태틱(static) 전역(global) 변수로 각각 Runnable, Thread 타입이다.

public class AlarmRunnable implements Runnable {

    @Override

    public void run() {

        try {

            Thread.sleep(60000);

        } catch (InterruptedException e) {

        } finally {

            alarmRunnable = null;

            alarmThread = null;

        }

    }

}

 

이를 이용하여 Thread를 종료시키려면 다음과 같이 하면 된다.

private void killAlarmThread() {

    try {

        alarmThread.interrupt();

        alarmThread.join();

    } catch(InterruptedException e) {

        e.printStackTrace();

    }

}

alarmThread.interrupt();가 실행 되면 잠자고있던(또는 실행하고 있던) 쓰레드가 이를 감지하여 catch(InterruptedException e) 실행부분으로 넘어가고, 위의 코드에서는 catch()에서 실행하는 것이 업서서 finally() 실행부분으로 넘어가면 다 실행되면 쓰레드는 종료된다.

 

alarmThread가 살아있을 때에만 강제 종료처리가 이루어지도록 불러보았다.

 ...

if (alarmRunnable != null && alarmThread != null) {

    killAlarmThread();

}

 ...

 

Reference

[1] http://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html

[2] http://stackoverflow.com/questions/10961714/how-to-properly-stop-the-thread-in-java

[3] http://baeksupervisor.tistory.com/31

[출처] Java: 쓰레드(Thread)를 중간에 종료시키는 방법|작성자 제오

번호 제목 글쓴이 날짜 조회 수
347 java.util.Optional 에서의 map() 함수의 이해 황제낙엽 2026.06.24 666
346 linux(ubuntu) 의 jdk 21 이 설정된 환경에서 jdk 17 로 다운그레이드 절차 황제낙엽 2025.09.22 1532
345 [ChatGPT] javax.* 패키지와 jakarta.* 패키지의 혼합 사용 방안 황제낙엽 2025.04.15 2458
344 [ChatGPT] *.servlet.http.HttpServlet 클래스를 사용할 수 있는 주요 WAS 목록 황제낙엽 2025.04.14 2038
343 [ChatGPT] JDBC API에서 java.sql과 javax.sql 패키지의 차이점 황제낙엽 2025.01.31 2218
342 jakarta.servlet 패키지를 이용한 File Upload 구현 (2024.03.03, Servlet 5.0) 황제낙엽 2025.01.02 2310
341 [ChatGPT] Java EE가 Jakarta EE로 전환 황제낙엽 2025.01.01 2525
340 [ChatGPT] File.delete() 함수로 파일 삭제가 되지 않는 경우 황제낙엽 2024.12.10 2809
339 [ChatGPT] <jsp:include>에서 flush="true"를 설정시의 몇 가지 문제점 과 대안 황제낙엽 2024.07.19 2493
338 [Copilot] JSP, Servlet, web.xml, mysql 한글 설정 황제낙엽 2024.07.12 2555
337 Base64 클래스의 encode, decode 에서 URL-safe 황제낙엽 2024.07.10 2624
336 [Copilot] JSP 에서 다른 페이지를 현재 페이지에 포함시키는 문법 (include) 황제낙엽 2024.06.26 2570
335 Exception 출력에 대한 고찰 황제낙엽 2024.06.10 2198
334 google-auth-library-oauth2-http 라이브러리 다운로드 황제낙엽 2023.11.19 4025
333 firebase-admin-java 라이브러리 다운로드 (firebase admin sdk library) 황제낙엽 2023.11.19 2805
332 Enum 활용 (개인블로그, Effective Java) file 황제낙엽 2023.11.02 2759
331 Enum 활용 (우아한기술블로그) file 황제낙엽 2023.11.02 2790
330 servlet name 에 camel case 를 사용해서는 안되는 이유 황제낙엽 2023.10.24 2508
329 org.apache.commons.fileupload.servlet.ServletFileUpload 이용 예시 황제낙엽 2023.08.25 3336
328 ServletFileUpload.parseRequest() 실행 결과 리스트가 비어있는 오류 황제낙엽 2023.08.25 2935