쓰레드 상태와 제어 메서드1 (sleep, interrupt)

KDG: First things first!·2024년 7월 31일
0

CS

목록 보기
2/6

쓰레드에도 상태가 존재하고 여러 메서드들을 통해 쓰레드들의 상태를 제어할 수 있다.



쓰레드 상태

new 연산자로 쓰레드 객체를 생성하고 start() 메서드를 실행하면 쓰레드는 실행 대기(RUNNABLE) 상태로 바뀌고 run() 메서드가 실행되면 쓰레드가 실행된다. 이후 프로세스에서 리소스를 할당받는 스케줄러에 의해서 완전히 종료될 때까지 실행되었다가 멈추고 실행 대기 상태되었다다시 실행되고 하는 것을 반복한다.


상태상수설명
객체생성NEW쓰레드 객체 생성(start() 이전)
실행대기RUNNABLE실행 대기 상태로 언제든지 실행 가능
실행RUNNING쓰레드 실행 중
일시정지WAITING다른 쓰레드가 통지(notify)할 때까지 대기
일시정지TIME_WAITING정해진 시간 동안 대기
일시정지BLOCKED사용하려는 객체의 Lock이 풀릴 때까지 대기
종료TERMINATED (DEAD)쓰레드 종료



쓰레드 제어 메서드

1. sleep()

sleep(): 현재 쓰레드를 지정된 시간 동안 멈추게 하며 쓰레드 자기자신만 멈추게 할 수 있다.

try {
        Thread.sleep(3000); // 현재 쓰레드 3초 정지(1000ms = 1초)
} catch (InterruptedException e) {
        e.printStackTrace();
}


public class Main {
    public static void main(String[] args) {
        Runnable task = () -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("task : " + Thread.currentThread().getName());
        };

        Thread thread = new Thread(task, "Thread");
        thread.start();

        try {
            thread.sleep(1000);
            System.out.println("sleep(1000) : " + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Thread.sleep()은 Thread 클래스의 static 메서드이기 때문에 특정 쓰레드만 지목불가능하고 결국 위의 코드에서는 현재 쓰레드인 Main 쓰레드에 sleep()이 적용된다.

(객체 thread.sleep()도 가능하지만 static 메서드이기 때문에 인스턴스 변수 참조해서 접근해봤자 어차피 클래스로 접근할 때랑 똑같이 작동하여 의미가 없어 권장되지는 않는다.)

또한 interrupt()를 만나면 sleep()을 깨뜨리고 쓰레드를 실행대기 상태로 보내기 때문에 InterruptedException이 발생할 수 있어 try-catch를 통한 예외 처리가 필수이다.



2. interrupt

interrupt(): 일시정지 상태인 쓰레드를 실행 대기 상태로 만든다.

public class Main {
    public static void main(String[] args) {
        Runnable task = () -> {
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("task : " + Thread.currentThread().getName());
        };

        Thread thread = new Thread(task, "Thread");
        thread.start(); // NEW 상태 -> RUNNABLE 상태

        thread.interrupt();

        System.out.println("thread.isInterrupted() = " + thread.isInterrupted());

    }
}

// 출력 결과
/*java.lang.InterruptedException: sleep interrupted

task : Thread
thread.isInterrupted() = true */
  

sleep()이 포함된 task를 실행하는 쓰레드 객체를 만들었다. 이후 start()로 쓰레드가 task를 수행하여 sleep()이 수행 중인데 interrupt()를 만나 sleep() 한 줄 아래의 출력문까지 이행하지 못하고 InterruptedException의 catch문으로 빠져버린다.

즉, sleep 상태일 때 interrupt()를 마주치면 InterruptedException이 발생하여 catch문이 실행된다.


public class Main {
    public static void main(String[] args) {
        Runnable task = () -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    break;
                }
            }
            System.out.println("task : " + Thread.currentThread().getName());
        };

        Thread thread = new Thread(task, "Thread");
        thread.start();

        thread.interrupt();

        System.out.println("thread.isInterrupted() = " + thread.isInterrupted());

    }
}

// 출력: 
/*task : Thread
thread.isInterrupted() = true */

위의 코드처럼 interrupated 상태인지 확인하는 isInterrupted()을 이용하면 interrupt()와 sleep()을 만나지 않게 하여 InterruptedException 예외가 나오지 않을 수 있따.

profile
알고리즘, 자료구조 블로그: https://gyun97.github.io/

0개의 댓글