스레드를 생성하고 시작하면 스레드는 다양한 상태를 가지게 됩니다. 스레드의 상태는 자동으로 변경될 수도 있고, 코드에 의해서 변경될 수도 있습니다. 이번 절에서는 스레드의 상태를 변경해서 스레드를 제어하는 방법에 대해 알아보겠습니다.
1. 스레드 상태
스레드 객체를 생성하고 start() 메소드를 호출하면 곧바로 스레드가 실행되는 것처럼 보이지만 사실은 실행 대기 상태가 됩니다. 실행 대기 상태에 있는 스레드 중에서 운영체제는 하나의 스레드를 선택하고 CPU(코어)가 run() 메소드를 실행하도록 합니다. 이때를 실행 상태라고 합니다. 실행 상태의 스레드는 run() 메소드를 모두 실행하기 전에 다시 실행 대기 상태로 돌아갈 수 있습니다. 그리고 실행 대기 상태에 있는 다른 스레드가 선택되어 실행 상태가 됩니다. 이렇게 실행 대기 상태와 실행 상태를 번갈아가면서 자신의 run() 메소드를 조금씩 실행합니다. 실행 상태에서 run() 메소드가 종료되면, 더 이상 실행할 코드가 없기 때문에 스레드의 실행은 멈추게 됩니다. 이 상태를 종료(terminated) 상태라고 합니다.
2. 스레드 상태 제어
사용자는 미디어 플레이어에서 동영상을 보다가 일시 정지할 수도 있고, 종료할 수도 있습니다. 이와 같이 실행 중인 스레드의 상태를 변경하는 것을 스레드 상태 제어라고 합니다.
sleep(밀리 세컨드) = 주어진 시간 동안 스레드를 일시 정지 상태로 만듭니다.
interrupt() = 일시 정지 상태의 스레드에서 InterruptedException을 발생시켜, 예외 처리 코드(catch)에서 실행 대기 상태로 가거나 종료 상태로 갈 수 있게 합니다.
stop() = 스레드 즉시 종료
try {
Thread.sleep(1000);
{ catch(InterruptedException e) {
//interrupt() 메소드가 호출되면 실행
}
일시 정지된 시간 동안 interrupt() 메소드가 호출되면 InterruptedException이 발생하기 때문에 예외 처리가 필요합니다.
다음은 스레드를 안전하게 종료시키는 방법에 관한 예제입니다.
다음은 interrupt()를 통한 스레드 종료 예제입니다.
주목할 점은 스레드가 실행 대기 또는 실행 상태에 있을 때 interrupt() 메소드가 실행되면 즉시 InterruptException이 발생하지 않고, 스레드가 미래에 일시 정지 상태가 되면 InterruptException이 발생한다는 것입니다. 따라서 스레드가 일시정지 상태가 되지 않으면 Interrupt() 메소드 호출은 아무런 의미가 없습니다. 그래서 짧은 시간이나마 일시 정지시키기 위해 Thread.sleep(1)을 사용한 것입니다.
하지만 일시 정지를 만들지 않고도 interrupt()의 호출 여부를 알 수 있는 방법이 있습니다. interrupt() 메소드가 호출되었다면 스레드의 interrupted()와 isInterrupted() 메소드는 true를 리턴합니다.
package sec06.exam06;
public class PrintThread1 extends Thread {
public void run() {
while(true) {
System.out.println("실행 중");
if(Thread.interrupted()) {
break;
}
}
System.out.println("자원 정리");
System.out.println("실행 종료");
}
}
3. 데몬 스레드
데몬 스레드는 주 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드입니다. 주 스레드가 종료되면 데몬 스레드는 강제적으로 종료됩니다. 데몬 스레드에는 워드프로세서의 자동저장, 미디어 플레이어의 동영상 및 음악 재생, 가비지 콜렉터 등이 있습니다.
스레드를 데몬으로 만들기 위해서는 주 스레드가 데몬이 될 스레드의 setDaemon(true)를 호출해 주면 됩니다. 아래 코드를 보면 메인 스레드가 주 스레드가 되고, AutoSaveTread()가 데몬 스레드가 됩니다.
주의할 점은 start() 메소드를 호출하고 나서 setDaemon(true)를 호출하면 IlligalThreadStateException()이 발생하기 때문에 start() 메소드 호출 전에 setDaemon(true)를 호출해야 한다는 것입니다.
다음 예제는 1초 주기로 save() 메소드를 자동 호출하도록 AutoSaveTread를 작성하고 메인 스레드가 3초 후 종료되면 AutoSaveTread도 같이 종료되도록 AutoSaveTread를 데몬 스레드로 만들었습니다.
'java' 카테고리의 다른 글
java 스택, 큐 (0) | 2021.01.30 |
---|---|
java 컬렉션 프레임워크 (0) | 2021.01.29 |
java.lang 패키지 (0) | 2021.01.28 |
java 예외 처리 - 예외 클래스 (0) | 2021.01.27 |
java 익명 객체 - 중첩 클래스와 중첩 인터페이스 (0) | 2021.01.26 |