이번에는 스레드 상태에 대해서 알아보도록 하겠습니다.

 

스레드 프로그래밍을 진행하다보면 동기화/비동기화 뿐만 아니라 스레드의 행동을 직접 제어해야 할 경우가 생깁니다.

 

1000장의 문서를 복사해야한다고 가정합니다.

공유된 프린터는 1개 밖에 없는데, 이 때 1000장을 전부 복사하는 동안 혼자서 쓸 수 없을 겁니다.

다른 사람들도 프린터를 사용해야 하는 경우가 분명 생길거에요.

그럴 때, 100장씩 복사를 하도록 하고, 그 때마다 다른 사람들이 사용하도록 통제할 수도 있을거에요.

 

이처럼 스레드도 상태를 제어해야 할 필요성이 있는데, 제어를 하기 전에 해당 스레드의 상태를 알아야 합니다.

그러기 위해서는 getState() 메서드를 사용하여 상태를 확인합니다.

 

□ 스레드 상태

    · 스레드는 start() 하게 되면 일반적으로 다음과 같은 상태로 진행 됩니다.

[그림 1 - 스레드의 일반적인 실행 상태]

 

    · 경우에 따라서 스레드는 실행 상태에서 실행 대기 상태로 가지 않을 수도 있습니다.

    · 실행 상태에서 일시 정지 상태로 가기도 하는데, 일시 정지 상태는 스레드가 실행할 수 없는 상태입니다.

    · 스레드가 다시 실행 상태로 가기 위해서는 일시 정지 상태에서 실행 대기 상태로 가야합니다.

 

[그림 2 - 스레드의 실행과 일시 정지 상태]

 

이처럼 프로그래밍 하면서 스레드의 상태를 알 수 있도록 해주는 메소드는 getState() 입니다.

getState()의 스레드 상태에 따른 Thread.State 열거 상수가 있는데 열거 상수는 다음의 표와 같습니다.

 

상태 열거 상수 설명
객체 생성 NEW 스레드 객체가 생성, 아직 start() 메소드가 호출되지 않은 상태
실행 대기 RUNNABLE 실행 상태로 언제든지 갈 수 있는 상태
일시 정지 WAITING 다른 스레드가 통지할 때까지 기다리는 상태
TIMED_WAITING 주어진 시간 동안 기다리는 상태
BLOCKED 사용하고자 하는 객체의 락이 풀릴 때까지 기다리는 상태
종료 TERMINATED 실행을 마친 상태

 

이제 프로그래밍을 통해 스레드의 상태를 직접 확인해 봅시다.

 

이 예제는 스레드의 상태를 출력해주며, 생성자 매개값으로 받은 타겟 스레드의 상태를 0.5초 주기로 출력 해주는 클래스 입니다.

 

 

 

StatePrintThread.java - 타겟 스레드의 상태를 출력하는 스레드

package thread_state;

public class StatePrintThread extends Thread {

	private Thread targetThread;
	
	public StatePrintThread(Thread targetThread) {
		this.targetThread = targetThread;
	}
	
	@Override
	public void run() {
		while(true) {
			Thread.State state = targetThread.getState();	// 스레드 상태 얻기
			System.out.println("타겟 스레드 상태: " + state);
			
			// 객체 생성 상태일 경우 실행 대기 상태로 만듬
			if(state == Thread.State.NEW) {
				targetThread.start();
			}
			
			// 종료 상태일 경우 while문을 종료함
			if(state == Thread.State.TERMINATED) {
				break;
			}
			try {
				Thread.sleep(500);
			} catch(Exception e) {}
		}
	}
}

 

 

다음은 타겟 스레드 클래스입니다.

10억 번 루핑을 돌게 해서 RUNNABLE 상태를 유지하고, sleep() 메소드를 호출해서 1.5초간 TIMED_WAITING 상태를 유지합니다.

또한 다시 10억 번 루핑을 돌게 해서 RUNNABLE 상태를 유지합니다.

 

 

TargetThread.java - 타겟 스레드

package thread_state;

public class TargetThread extends Thread {

	@Override
	public void run() {
		for(long i=0; i<1000000000; i++) {}
		
		try {
			Thread.sleep(1500);
		} catch(Exception e) {}
		
		for(long i=0; i<1000000000; i++) {}
	}
}

 

TargetThread가 객체로 생성되면 NEW 상태를 가지고, run() 메소드가 종료되면 TERMINATED 상태가 되므로 결국 다음과 같은 상태로 변합니다.

 

NEW -> RUNNABLE -> TIMED_WAITING -> RUNNABLE -> TERMINATED

 

다음은 StatePrintThread를 생성해서 매개값으로 전달받은 TargetThread의 상태를 출력하는 클래스입니다.

 

 

 

ThreadStateExample.java - 실행 클래스

package thread_state;

public class ThreadStateExample {

	public static void main(String[] args) {
		StatePrintThread statePrintThread = 
				new StatePrintThread(new TargetThread());
		statePrintThread.start();
	}
}

 

실행을 하면

 

타겟 스레드 상태: NEW

타겟 스레드 상태: RUNNABLE

타겟 스레드 상태: RUNNABLE

타겟 스레드 상태: TIMED_WAITING

타겟 스레드 상태: TIMED_WAITING

타겟 스레드 상태: TIMED_WAITING

타겟 스레드 상태: RUNNABLE

타겟 스레드 상태: RUNNABLE

타겟 스레드 상태: RUNNABLE

타겟 스레드 상태: TERMINATED

 

이와 같은 실행 결과를 확인할 수 있다.. 고 이것이 자바다에 나와 있습니다.

 

저는 다음과 같은 상태변화만 확인할 수 있었습니다.

 

타겟 스레드 상태: NEW

타겟 스레드 상태: TIMED_WAITING

타겟 스레드 상태: TIMED_WAITING

타겟 스레드 상태: TIMED_WAITING

타겟 스레드 상태: RUNNABLE

타겟 스레드 상태: TERMINATED

 

제가 자세하게 안다면 이와 같은 현상에 대해서 자세하게 알 수 있을텐데 아직 많이 부족하여 잘 모르겠네요..

첫 번째 10억 번 루핑도는 부분에서 상태가 잡히지 않는 것 같습니다.

출력을 찍어보면 정상적으로 되는 것 같은데 해당 상태가 RUNNABLE이 맞다고 생각하는데 첫 번째 루핑 넘어간 다음 sleep()으로 바로 넘어가서 TIMED_WAITING이 출력되네요.

 

시스템 환경을 다양하게해서 확인해 봐야 할 것 같습니다.

 

 

+ Recent posts