이전 포스팅에선 다음과 같이 알아 봤는데요

  • Thread 생성
  • Thread 동기화 블록

이번에는 Thread가 제공하는 몇가지 메서드를 확인해보고
Thread 상태를 제어하는 방법에 대해 알아보도록 하겠습니다


Thread 상태

스레드를 생성하고 start() 메서드를 호출하면 곧바로 스레드가 실행되는 것처럼 보이지만, 사실은 '실행대기' 상태가 됩니다.
실행대기 상태란 아직 스케줄링이 되지 않아 실행을 기다리고 있는 상태를 말합니다.
실행대기 상태에 있는 스레드 중에서 스케줄링으로 선택된 스레드가 비로서 CPU를 점유하고 run() 메서드를 실행하게 됩니다.
이때를 실행 상태라고 합니다.

아래의 사진으로 스레드의 대략적인 상태를 살펴 보겠습니다

실행 상태의 스레드는 다시 실행대기 상태로 돌아갈 수 있고
실행, 실행대기 상태를 번갈아가며 자신의 run() 메서드를 수행합니다.
run() 메서드가 종료되면 스레드의 실행은 멈추게 됩니다.
이 상태를 종료 상태라고 합니다

경우에 따라서 ‘실행상태’에서 ‘일시정지’ 상태로 가기도 하는데,
일시정지 상태에서는 스레드가 실행할 수 없는 상태입니다.
일시정지 상태로는 WAITING, TIMED_WAITING, BLOCKED가 있습니다.
스레드가 다시 실행 상태로 가기 위해서는 일시정지 상태에서 실행대기 상태가 되어야 합니다.

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

스레드의 상태 제어

사용자는 미디어 플레이어에서 동영상을 보다가 일시 정지 시킬수도 있고, 종료시킬수도 있습니다
정지는 다시 동영상을 보겠다는 의미로 스레드를 일시정지 상태로 만들어야 합니다
종료는 더 이상 동영상을 보지 않겠다는 의미이므르 미디어 플레이어는 스레드를 종료 상태로 만들어야 합니다
이와 같이 스레드의 상태를 변경하는 것은 스레드 상태 제어라고 합니다

아래는 스레드 상태를 제어하는 메서드입니다. 하나씩 메서드를 알아보도록 하겠습니다

일시정지 (sleep)

sleep() - 주어진 시간동안 일시 정지 상태로 만들고, 주어진 시간이 지나면 자동적으로 실행대기 상태가 됩니다
try {
    Thread.sleep(3000);
} catch (InterruptedException e) {
    e.printStackTrace();
} 

Thread.sleep(3000) 메서드를 통해 3초간 ‘일시정지’ 상태가 되고 3초가 지나면 다시 ‘실행대기’ 상태로 돌아오게 됩니다.

실행 양보 (yield)

yield() - 실행중에 우선순위가 높은 또는 동일한 다른 스레드에게 실행을 양보하고 실행 대기 상태가 됩니다
if (work) {
    System.out.println(getName() + " 스레드 작업 내용");
} else {
    Thread.yield();
}

yield() 메서드 호출시 해당 Thread는 우선 순위가 높거나 동일한 Thread에게 실행을 양보하고 실행 대기 상태로 전환됩니다

다른 스레드의 종료를 기다림 (join)

join() -메서드를 호출한 스레드는 일시 정지 상태가 됩니다. 실행 대기 상태로 가려면 join() 메서드를 멤버로 가지는 스레드가 종료되거나, 매개값으로 주어진 시간이 지나야 합니다. 이부분은 예제를 보도록 하겠습니다
SumThread
public class SumThread extends Thread {
    private long sum;
    public long getSum() {
        return sum;
    }

    public void run() {
        for (int i = 1; i <= 100; i++) {
            sum += i;
        }
    }
}
JoinExample
public class JoinExample {
    public static void main(String[] args) {
        SumThread sumThread = new SumThread();
        sumThread.start();

        try {
            sumThread.join();
        } catch (Exception e) {
        }

        System.out.println("합 : " + sumThread.getSum());
    }
}

sumthread.join()을 걸어 두었기 때문에 메인 Thread는 합연산이 끝날때까지 기다리게 됩니다. 따라서, 결과값은 5050이 나오게 됩니다

여기서 의문이 들 수 있습니다. Thread.sleep(3000)으로도 충분히 가능한데 무엇이 차이인가? sleep은 일정 시간동안만 실행대기 상태로 만들어줍니다. join의 경우 thread의 작업을 처리할때까지 묶어 둘 수 있기 때문에 멀티스레드 환경에서 동기화를 맞춰야 할 경우 유용하게 사용할 수 있습니다.

스레드간 협업 (wait, notify, notifyAll)

notify, notifyAll - 동기화 블록 내에서 wat 메서드에 의해 일시 정지 상태에 있는 스레드를 실행 대기 상태로 만들어 줍니다
wait - 동기화 블록 내에서 스리드를 일시 정지 상태로 만듭니다. 매개값으로 시간이 주어지면 일정 시간이 지난후 자동으로 실행대기 상태가 되고, 시간이 주어지지 않으면 notify, notifyAll 메서드에 의해 실행 대기 상태로 갈 수 있습니다

스레드 종료 (stop, interrupt)

Thread는 자신의 run() 메서드가 모두 실행되면 자동으로 종료됩니다. 경우에 따라서 Thread를 즉시 종료할 필요가 있습니다

stop - 갑자기 종료하면 스레드가 사용중이던 자원들이 불안전한 상태로 남겨지기 때문에 deprecated 되었습니다
interrupt - 일시 정지 상태의 스레드에서 InterruptedException 예외를 발생시켜, 예외 처리 코드(catch)에서 실행 대기 상태로 가거나 종료 상태로 갈 수 있도록 합니다

참조

  • '이것이 자바다' - 신용권님 저
블로그 이미지

yhmane

댓글을 달아 주세요