본문 바로가기

Programming/JAVA

멀티 스레드(6) - 스레드 상태 제어 3

 

 

 

 

○ 다른 스레드에게 실행 양보하기( yield( ) )

 

 

스레드 처리 작업은 반복적인 실행 상태 유지를 위하여 for문 또는 while문을 사용하는 경우가 많습니다. 그런데, 이러한 반복문이 무의미하게 반복이 유지되는 경우가 있습니다. 

 

public void run() {
	while(true) {
    	if(work) {
        	System.out.println("ThreadA 작업 내용");
        }
    }
}

 

 

위와 같은 while문이 있다고 가정해 보겠습니다. 스레드가 실행되어 run( )이 실행되면, while(true) { } 블록은 무한 반복 실행이 됩니다. 

 

그런데 이 때, work가 true가 아니라 false라면? 그리고 work가 false에서 true 바뀌는 상황이 정확히 선언되어있지 않다면? 해당 스레드는 while문에서 아무것도 실행되지 않는 상태가 덩그러니 무한반복 되는 상태에 빠지게 됩니다. 극단적인 사례이지만, 이처럼 적절한 타이밍에(여기서는 work가 false인 상황) 다른 스레드로 실행을 양보하고, 자신은 실행 대기 상태로 전환되는 것이 바람직할 것입니다. 

 

이럴 때 yield( )를 사용하게 되는데, yield( )를 호출하게 되는 스레드는 실행 대기 상태로 전환되고, 동일한 or 높은 우선순위의 다른 스레드가 실행 기회를 갖게 됩니다.

 

간단하게 위의 예제에 yield( ) 적용시키면, 아래와 같이 사용할 수 있습니다. 

 

public void run() {
	while(true) {
    	if(work) {
        	System.out.println("ThreadA 작업 내용");
        } else {
        	Thread.yield();
    }
}

 

조금 더 구체적인 예제를 작성해 보겠습니다. 

 

 

 


 

 

// ThreadA.java
public class ThreadA extends Thread {
	// 스레드 종료 플래그
	public boolean stop = false;
	// 작업 진행 여부 플래그
	public boolean work = true;
	
	public void run() {
		while(!stop) {
			if(work) {
				System.out.println("ThreadA 작업 사항");
			} else {
				Thread.yield();
			}
		}
		System.out.println("ThreadA 종료");
	}
}

 

 

// ThreadB.java
public class ThreadB extends Thread {
	// 스레드 종료 플래그
	public boolean stop = false;
	// 작업 진행 여부 플래그
	public boolean work = true;
	
	public void run() {
		while(!stop) {
			if(work) {
				System.out.println("ThreadB 작업 사항");
			} else {
				Thread.yield();
			}
		}
		System.out.println("ThreadB 종료");
	}
}

 

 

public class ExampleMain {
	public static void main(String[] args) {
		ThreadA threadA = new ThreadA();
		ThreadB threadB = new ThreadB();
		
		threadA.start();
		threadB.start();
		
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) { }
		threadA.work = false;
		
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) { }
		threadA.work = true;
		
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) { }
		threadA.stop = true;
		threadB.stop = true;
	}
}

 

- 처음 실행 후 3초간 ThreadA와 ThreadB 번갈아 실행

- 3초 뒤 ThreadA의 work 필드 false로 변경하고, ThreadA는 yield( ) 메서드 호출

- 이후 3초간 ThreadB가 더 많은 실행 기회

- 다시 3초 뒤 메인스레드는 다시 ThreadA의 work  필드 true로 변경

- ThreadA, ThreadB 동시 번갈아 실행

- 마지막으로 3초 뒤 메인 스레드는 ThreadA와 ThreadB의 stop 필드를 true로 변경해 종료