티스토리 뷰

언어/Java

[Java]쓰레드 상태(Thread State)와 메서드에 대하여

꼬마우뇽이(원종운) 2021. 12. 31. 17:08

1편 - 쓰레드(Thread)에 대하여

2편 - 쓰레드 상태(Thread State)와 메서드에 대하여 - 현재 글

3편 - 쓰레드 동기화(Thread Synchronization)에 대하여

4편 - 쓰레드 풀(Thread Pool)에 대하여

5편 - ThreadExecutor에 대하여

6편 - ForkJoinPool에 대하여

 


쓰레드의 상태

Java에서 쓰레드의 상태를 나타내는 열거형은 다음과 같습니다. 총 6가지의 상태가 존재합니다.

public enum State {
        NEW,
        RUNNABLE,
        BLOCKED,
        WAITING,
        TIMED_WAITING,
        TERMINATED;
}

 

상태 열거 상수 설명
쓰레드 객체 생성 NEW  쓰레드가 아직 시작(start) 되지 않은 상태
실행 대기 RUNNABLE 쓰레드가 실행 가능한(Runnable) 상태
일시 정지 WAITING 다른 쓰레드가 특정 작업을 수행하기를 기다리는 상태
(Object.wait without timeout, Thread.join without timeout, ... 와 같은 작업)
TIMED_WAITING 지정된 대기 시간 동안 대기하는 상태
(Thread.sleep, Object.wait with timeout, Thread.join with timeout, ... 에 의하여 지정된 대기) 
BLOCKED 모니터 락(monitor lock)을 기다리는 동안 차단(Blocked) 된 상태
종료 TERMINATED 쓰레드가 실행이 완료되어 종료(Terminated) 한 상태

 

쓰레드의 상태를 어떻게 확인할 수 있을까?

Runnable 인터페이스를 구현하여 쓰레드를 구성한 경우는 Thread.currentThread().getState() 메서드를 이용하여 쓰레드의 상태를 확인할 수 있습니다. Thread 클래스를 상속받아 구성한 경우는 전자의 방법도 되고, 부모의 getState() 메서드를 바로 이용하면 됩니다.

 

쓰레드의 상태를 직접 확인해봅시다.

다양한 쓰레드 상태를 코드를 통해서 확인해보도록 하겠습니다.

 

class MyThread extends Thread {

    private Thread target;

    public MyThread(String name, Thread target) {
        super(name);
        this.target = target;
    }

    @Override
    public void run() {
        for(int i = 0; i <= 2_000_000_000; i++);
        for(int i = 0; i <= 2_000_000_000; i++);
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            target.join(); // target 쓰레드가 종료될 때까지 기다린다.
        } catch (InterruptedException e) {
            for(int x = 0; x <= 2_000_000_000L; x++);
            for(int x = 0; x <= 2_000_000_000L; x++);
        }
    }
}

public class App {
    private static Thread myThread1;
    private static Thread stateThread;

    public static void main(String[] args) {
        stateThread = new Thread(() -> {
            while(true) {
                State state = myThread1.getState();
                System.out.printf("[%s] - Threading.... - [%s]\n", myThread1.getName(), state);

                if (state == State.NEW) {
                    myThread1.start();
                }

                if (state == State.WAITING) {
                    myThread1.interrupt();
                }

                if (state == State.TERMINATED) {
                    System.out.printf("[%s] - Threading.... - [%s]\n", myThread1.getName(),  state);
                    break;
                }

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        myThread1 = new MyThread("myThread1", stateThread);
        stateThread.start();
    }
}

위의 코드를 실행하였을 때 myThread1의 상태가 어떤 식으로 변경될지 대강 흐름을 읽을 수 있어야 합니다. 대강이라고 한 이유는 쓰레드 스케쥴링에 따라 결과가 다를 수 있기 때문입니다.

 

과연 쓰레드의 상태는 어떻게 변하는가.

 

쓰레드 객체를 생성하였을 때는 NEW 상태로, sleep 메서드를 통하여 쓰레드를 멈출 경우는 TIMED_WAITING 상태로 전이된 것을 알 수 있습니다. myThread1 내부에서 join 메서드 호출로 다른 쓰레드에게 작업을 위임하였으므로 WAITING 상태로 전이된 것을 확인할 수 있습니다. WAITING 상태로 전이된 myThread1이 어떻게 RUNNABLE 상태로 전이될 수 있었을까요?

 

stateThread에서 myThread1이 WAITING 상태일 경우 interrupt 메서드를 호출하여 깨워줬기 때문입니다. 따라서 WAITING 상태에서 RUNNABLE 상태로 전이가 된 것이죠.

 

그리고 myThread1이 모든 작업이 완료되어서 종료되어 TERMINATED 상태로 전이된 것을 최종적으로 확인할 수 있었습니다.

 

각 상태들이 어떻게 전이되는지를 상태 전이도를 통하여 알아보겠습니다.

쓰레드 메서드

sleep 메서드

현재 실행 중인 쓰레드를 일정 시간 동안 일시 정지시킵니다. sleep 메서드를 호출할 경우 TIME_WAITING 상태로 전이되며, 일정 시간이 끝나거나 interrupt 메서드가 호출될 경우 RUNNABLE 상태로 전이됩니다. 그러므로 InterruptException을 예외를 처리해주어야 합니다.

public static native void sleep(long millis) throws InterruptedException;
public static void sleep(long millis, int nanos) throws InterruptedException;

 

join 메서드

현재 쓰레드를 일시 정지시킨 후, 특정 쓰레드가 일정 시간 동안 실행되도록 합니다. 시간을 명시하지 않을 경우 특정 쓰레드가 종료될 때까지 현재 쓰레드를 일시 정지시킵니다. 

 

만약 시간을 명시하지 않을 경우 WATING 상태로 전이되며, 시간을 명시할 경우 현재 쓰레드는 TIME_WATING 상태로 전이됩니다.

public final void join() throws InterruptedException { join(0); }
public final synchronized void join(long millis) throws InterruptedException;

 

interrupt 메서드

특정 쓰레드의 interrupt 플래그를 false -> true로 변경합니다. 만약 특정 쓰레드가 WAITING 또는 TIME_WAITING 상태에 있다면 InterruptException을 발생시킵니다. 이 말은 일시 정지 상태로 전이되었던 쓰레드를 RUNNABLE 상태로 전이시키는 것을 의미합니다. 

 

메서드 명의 의미는 쓰레드의 실행을 중단하는 것이지만 중단 요청의 의미로 InterruptException을 발생시키지만, 쓰레드의 실행을 중단할지는 해당 쓰레드의 책임입니다.

public void interrupt();

 

isInterrupted 메서드

현재 쓰레드의 실행이 중단(Interrupt)되었는지 여부를 반환하여줍니다.

public boolean isInterrupted();

 

yield 메서드

현재 실행 중인 쓰레드가 자신에게 할당된 작업 시간을 양보함을 스케쥴러에게 통보합니다.

public static native void yield();

 

state 메서드

해당 쓰레드의 상태를 반환하여 줍니다.

public State getState();

 

마무리

다음 3편에서는 쓰레드 동기화(Thread Synchronization)에 대하여 알아보도록 하겠습니다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함