BE전문가 프로젝트

16-2 스레드 - 제어 본문

JAVA

16-2 스레드 - 제어

원호보고서 2023. 11. 21. 20:41

이전 포스팅에서 스레드를 사용하기 위해 스레드.start() 메소드를 사용했다.

사실 start() 메소드를 호출한다고 해서 스레드가 곧바로 실행되는 것은 아니다. 실행 대기 상태가 되어 실행이 되기를 기다리는 상태가 된다. 운영체제에서는 실행대기 생태에 있는 스레드 중 하나를 선택하여 CPU가 run() 메소드를 실행하여 실행 상태(running)로 만든다.

 

상태
구분 내용
초기 상태 NEW 스레드 객체를 생성한 상태
실행 가능  RUNNABLE start()메서드로 스레드를 실행할 수 있는 상태
실행 중 RUNNING 실행가능한 스레드 중에서 스케줄러가 선택하여 스레드가 실행 중인 상태. CPU에 의해 코드가 한줄씩 실행된다. CPU는 n개의 스레드 중 1개밖에 처리할 수 없으며 n-1개의 스레드는 대기상태가 된다
대기상태 WATING 실행 중지. 다른 스레드의 통보(notify)를 기다리는 상태
TIMED_WATING 실행 중지. 주어진 시간동안 대기상태
BLOCKED 다른 스레드에 의해 락이 걸린 상태
종료 TERMINATED 스레드가 종료된 상태(한번 종료가 되면 다시 시작 X)

 

실행 상태의 스레드는 run() 메서드를 모두 실행하기 전에 다시 실행 대기 상태로 돌아갈 수 있으며 실행 대기에 있는 다른 스레드가 메모리를 할당받아 실행 상태가 된다.

 

실행 상태와 실행대기 상태를 여러번 번갈아가며 run()메소드를 조금씩 실행하는 원리이다. 모든 작업을 마치면 종료 상태가 된다.

 

스레드 상태 제어

멀트 스레드 프로그렘은 정교한 스레드 상태 제어가 필수적이다.

메소드 설명
interrupt() 일시 정지 상태의 스레드에서 InterruptedException 예외를 발생시켜, 예외 처리 코드(catch)에서 실행 대기 상태로 가거나 종료 상태로 갈 수 있도록 한다.
sleep(long millis)
sleep(long millis, int nanos)
주어진 시간 동안 스레드를 일시 정지 상태로 만든다. 주어진 시간이 지나면 자동적으로 실행 대기 상태가 된다.
notify()
notifyAll()
동기화 블록 내에서 wait() 메소드에 의해 일시 정지 상태에 있는 스레드를 실행 대기 상태로 만든다.
join()
join(long millis)
join(long millis, int nanos)
join() 메소드를 호출한 스레드는 일시 정지 상태가 된다. 실행 대기 상태로 가려면, join() 메소드를 멤버로 가지는 스레드가 종료되거나, 매개값으로 주어진 시간이 지나야 한다.
wait()
wait(long millis)
동기화(synchronized) 블록 내에서 스레드를 일시 정지 상태로 만든다. 매개값으로 주어진 시간이 지나면 자동적으로 실행 대기 상태가 된다. 시간이 주어지지 않으면 notify(), notifyAll() 메소드에 의해 실행 대기 상태로 갈 수 있다.
yield() 실행 중에 우선순위가 동일한 다른 스레드에게 실행을 양보하고 실행 대기 상태가 된다.
resume() - Deprecated suspend(0 메소드에 의해 일시 정지 상태에 있는 스레드를 실행 대기 상태로 만든다.
 (대신 notify(), notifyAll() 사용)
stop() - Deprecated 스레드를 즉시 종료시킨다.
불안정한 종료를 유발함으로 시용 지양 

 

위에서 나온  Deprecated는 스레드의 안정성을 해칠 위험이 있기에 사용하지 않도록 권장된 메소드들이다.

 

interrupt()

스레드가 일시정지 상태에 있을 때 InterruptedException을 발생시키는 역할을 한다. try catch를 이용하여 스레드의 run을 정상적으로 종료시킬 수 있다.

public class Task1 extends Thread {

    @Override
    public void run(){
        try {
            while (true) {
                System.out.println("실행중");
                Thread.sleep(1); //일시 정지 상태를 만들기 위함
            }
        } catch (InterruptedException e) {
            System.out.println("인터럽트 발생");
        }
        System.out.println("자원 정리");
        System.out.println("종료");
    }
}
public class HelloWorld {

    public static void main(String[] args) {

        Thread thread = new Task1();
        thread.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
        thread.interrupt();
    }
}

스레드는 일시정지 상태가 됐을 때만 interrupt를 발생시킨다. 따라서 일시정지를 하지 않는다면 interrupt()는 의미 없는 메소드가 될 뿐이다.

 

interrupted()와 isInterrupted()메소드를 통하여 interrupt()메소드가 호출 됐는지를 알 수 있다.

기능상 둘의 차이는 없고 interrupted()는 정적 메소드로 현재 스레드가 interrupted 됐는지 확인하는 것이고, isInterrupted()는 인스턴스 메소드로 확인하는 방법이다.

public class Task1 extends Thread {

    @Override
    public void run(){
        while (true) {
            if(Thread.interrupted()) {
                break;
            }
        }
    }
}

 

sleep()

스레드를 일시정지 하고 싶다면 Thread.sleep(1/1000초)로 일시정지 시킬 수 있다. 주어진 시간이 모두 지나가면 다시 실행 대기 상태로 돌아간다.

 

 

스레드 종료

run() 메소드가 모두 실행되고나면 스레드는 자동으로 종료된다. 하지만 그 전에 스레드를 종료해야하는 상황이 올 수도 있다. 

 

즉시 종료하기 위해서는 stop()이라는 메소드가 있는데 불안정한 종료를 유발할 뿐만 아니라 사용 중이던 자원들이 불안정한 상태로 남겨질 가능성이 있다.

  1. interrupt()함수를 이용하는 방법
  2. 플래그 이용
public class Task1 extends Thread {
    
    private boolean stop;
    
    @Override
    public void run(){
        while (!stop) {

        }
    }
}

while문을 이용하여 스레드의 흐름을 종료시키는 플래그를 사용한다.

 

 

'JAVA' 카테고리의 다른 글

18. 보조 스트림  (2) 2023.11.23
17. 입출력 스트림  (1) 2023.11.23
16-1. 스레드 - 멀티스레드  (2) 2023.11.20
15. java.lang에 대하여  (0) 2023.11.15
14. Object 클래스(hashcode() 및 equals())  (0) 2023.11.15
Comments