제가 공부하며 정리하는 글에서 마지막으로 구분한 스레드 상태 제어 part 3입니다.

 

 

스레드 상태, 스레드 상태 제어 part 1, 2는 다음의 링크를 통해 제 글을 확인하고 와주세요!

 

 

 

 

Java - 스레드 상태(Thread State)

 

Java - 스레드 상태 제어 (Thread State Control) part 1

 

Java - 스레드 상태 제어 (Thread State Control) part 2

 


 

part 3에서는 정지와 관련된 스레드의 안전한 종료(stop 플래그, interrupt())에 대해서 알아보도록 하겠습니다.

 

 

 

스레드는 자신의 run() 메소드가 모두 실행되면 자동적으로 종료 됩니다.

(저번 글(Java - 스레드 상태 제어 (Thread State Control) part1)에서 notify()와 wait()의 사용 예제를 작성해보며 run()메소드가 모두 실행이 되었음에도 불구하고, 계속 살아 있었던 경우가 있었습니다(자동적으로 종료 되지 않았습니다). 그 부분을 이번 글에서 나온 내용을 바탕으로 해결하였습니다.)

 

 

스레드 상태에 대하여 작성했던 내용 중에 stop() 메소드를 사용하면 스레드를 즉시 종료시킬 수 있다고 했었는데, 그 메소드는 deprecated 되었다고 했습니다. 그 이유는 stop() 메소드로 스레드를 갑자기 종료하게 되면 스레드가 사용 중이던 자원들이 불안전한 상태로 남겨지기 때문이라고 합니다.

 

 

stop 메소드 대신 stop 플래그를 이용하는 방법과 interrupt() 메소드를 이용하는 방법이 있습니다.


우선 stop 플래그를 이용하는 방법에 대하여 알아보겠습니다.

 

다음과 같이 간단하게 이해하시면 되지 않을까 싶습니다.

 

===============

while(조건) {

    실행 문장

}

===============

 

위의 while 문에서 조건 부분이 이면 실행이 되고, 거짓이면 실행이 되지 않는 점을 이용합니다.

 

예를들어 다음과 같이 활용할 수 있습니다.

 

===============

private boolean stop;

 

public void run() {

    while ( !stop ) {

        스레드가 반복 실행하는 코드;

    }

    //스레드가 사용한 자원 정리

}

===============

 

이처럼 stop이 true가 되면 while이 종료됩니다.

while을 빠져나오게 되면 스레드가 사용한 자원을 정리하게 되고, run() 메소드가 끝나게 되면서 스레드는 안전하게 종료됩니다.

 

다음 예제를 통해 stop 플래그를 사용해 보도록 하겠습니다.

 

 

 

 

 

StopFlagExample.java - 1초 후 출력 스레드를 중지시킴

package thread_state_control_3;
 
public class StopFlagExample {
 
    public static void main(String[] args) {
        PrintThread1 printThread = new PrintThread1();
        printThread.start();
        
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        
        printThread.setStop(true);    // 스레드를 종료시키기 위해 stop 필드를 true로 
    }
}

 

 

 

 

PrintThread1.java - 무한 반복해서 출력하는 스레드

package thread_state_control_3;
 
public class PrintThread1 extends Thread {
 
    private boolean stop;
    
    public void setStop(boolean stop) {
        this.stop = stop;
    }
    
    @Override
    public void run() {
        while(!stop) {
            System.out.println("실행 중");
        }
        System.out.println("자원 정리");    // stop이 true가 될 때
        System.out.println("실행 종료");
    }
}

 

예제를 실행하게 되면 다음과 같은 결과를 나오는 것을 확인할 수 있습니다.

 

실행 중

실행 중

실행 중

...

실행 중

자원 정리

실행 종료

 


다음으로 interrupt() 메소드를 이용하는 방법에 대하여 알아보도록 하겠습니다.

 

- interrupt() 메소드는 스레드가 일시 정지 상태에 있을 때 InterruptedException 예외를 발생시키는 역할을 합니다.

 

말보다 눈으로 직접 보는게 나을 수도 있지요!

 

다음의 [그림]을 보도록 하겠습니다.

 

[그림 interrupt() 발생 시 스레드의 상태]

ThreadA가 ThreadB의 interrupt() 메소드를 실행하게 되면 ThreadB가 sleep() 메소드로 일시 정지 상태가 될 때 ThreadB에서 InterruptedException이 발생하여 예외 처리(catch) 블록으로 이동합니다.

 

결과적으로 ThreadB는 while문을 빠져나와 run() 메소드를 정상 종료하게 됩니다.

* interrupt() 메소드가 sleep()(일시 정지)을 발생 시키지 않습니다! interrupt()라는 신호를 보내주는 거에요!

* 스레드 상태 제어 part 2 에서 이러한 방법을 이용하여 스레드를 종료하였습니다.

 

 

다음 예제를 통하여 사용해 보겠습니다.

 

 

 

InterruptExample - 1초 후 출력 스레드를 중지시킴

package thread_state_control_3;
 
public class InterruptExample {
 
    public static void main(String[] args) {
        Thread thread = new PrintThread2();
        thread.start();
        
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        
        thread.interrupt();    // 스레드를 종료시키기 위해 InterruptedException을 발생시킴
    }
}

 

 

 

PrintThread2.java - 무한 반복해서 출력하는 스레드

package thread_state_control_3;
 
public class PrintThread2 extends Thread {
 
    @Override
    public void run() {
        try {
            System.out.println("실행 중");
            Thread.sleep(1);    // InterruptedException 발생
        } catch (InterruptedException e) {
        }
        
        System.out.println("자원 정리");
        System.out.println("실행 종료");
    }
}

 

★ 여기서 주목하실 점은 스레드가 실행 대기 또는 실행 상태에 있을 때 interrupt() 메소드가 실행되면 즉시 InterruptedException 예외가 발생하는게 아닙니다!

    스레드가 미래에 일시 정지 상태가 되면 InterruptedException 예외가 발생합니다. 그러므로 스레드가 일시 정지 상태가 되지 않으면 interrupt() 메소드 호출은 아무런 의미가 없습니다.

 

 

일시 정지를 하지 않고도 interrupt() 호출 여부를 알 수 있는 방법이 있습니다.

interrupt() 메소드가 호출되었다면 스레드의 interrupted()와 isInterrupted() 메소드는 true를 리턴합니다.

 

바로 위 예제의 PrintThread2.java 를 수정하여 interrupted를 사용하도록 해보았습니다.

 

 

 

 

PrintThread2.java - 수정된 코드

package thread_state_control_3;
 
public class PrintThread2 extends Thread {
 
    @Override
    public void run() {
        while(true) {
            System.out.println("실행 중");
            if(Thread.interrupted()) {
                break;
            }
        }
        
        System.out.println("자원 정리");
        System.out.println("실행 종료");
    }
}

 

interrupted()를 stop 플래그 처럼 활용하는 방법입니다.

 

 


스레드 상태 제어는 세분화하면 더욱 다양하지만 저는 일단 여기까지를 기본 개념으로 보고 있습니다.

나머지는 상태 제어는 맞지만 개념 자체가 상태 제어도 포함하지만 어떻게 보면 다른 개념처럼 보일 수도 있기에 따로 개념을 정리하였습니다.

 

이후 데몬 스레드, 스레드 그룹, 스레드풀의 형식으로 글을 작성하도록 하겠습니다.

 

 

 

 

 

 

+ Recent posts