운영체제

Thread - interrupt

으엉어엉 2024. 12. 14. 12:50
728x90
import static util.MyLogger.log;
import static util.ThreadUtils.sleep;

public class ThreadStopMainV1 {
    public static void main(String[] args) {
        MyTask task = new MyTask();
        Thread thread = new Thread(task, "work");
        thread.start();
        sleep(4000);
        log("작업 중단 지시 runFlag=false");
        task.runFlag = false;
    }
    static class MyTask implements Runnable {
        volatile boolean runFlag = true;
        @Override
        public void run() {
            while (runFlag) {
                log("작업 중");
                sleep(3000);
            }
            log("자원 정리");
            log("작업 종료");
        }
    }
}

work 스레드는 runFlag 의 조건이 false 로 변한 것을 확인하고, while문을 빠져 나가면서 작업을 종료한다.

인터럽트를 사용하면, WAITING,   TIMED_WAITING 같은 대기 상태의 스레드를 직접 깨워서, 작동하는 RUNNABLE 상태로 만들 수 있다.

 

@Override
public void run() {
    try {
        while (true) {
            log("작업 중");
            Thread.sleep(3000);
        }
    }
    catch (InterruptedException e) {
        log("work 스레드 인터럽트 상태2 = " + Thread.currentThread().isInterrupted());
        log("interrupt message=" + e.getMessage());
        log("state=" + Thread.currentThread().getState());
    }
    log("자원 정리");
    log("작업 종료");
}

이때 인터럽트를 받은 스레드는 대기 상태에서 깨어나 RUNNABLE 상태가 되고, 코드를 정상 수행한다.

 

work 스레드는 인터럽트 상태가 되었고, 인터럽트 상태이기 때문에 인터럽트 예외가 발생한다.

 

import static util.MyLogger.log;
import static util.ThreadUtils.sleep;
public class ThreadStopMainV4 {
    public static void main(String[] args) {
        MyTask task = new MyTask();
        Thread thread = new Thread(task, "work");
        thread.start();
        sleep(100); //시간을 줄임
        log("작업 중단 지시 - thread.interrupt()");
        thread.interrupt();
        log("work 스레드 인터럽트 상태1 = " + thread.isInterrupted());
    }
    static class MyTask implements Runnable {
        @Override
        public void run() {
            while (!Thread.interrupted()) { //인터럽트 상태 변경O
                log("작업 중");
            }
            log("work 스레드 인터럽트 상태2 = " +Thread.currentThread().isInterrupted());
            try {
                log("자원 정리 시도");
                Thread.sleep(1000);
                log("자원 정리 완료");
            }
            catch (InterruptedException e) {
                log("자원 정리 실패 - 자원 정리 중 인터럽트 발생");
                log("work 스레드 인터럽트 상태3 = " +
                        Thread.currentThread().isInterrupted());
            }
            log("작업 종료");
        }
    }
}

Thread.interrupted() 를 호출했을 때 스레드가 인터럽트 상태 (true) 라면 , true 반환, 해당 스레드의 인터럽트 상태를 false로 변경한다. 결과적으로 while문을 탈출하는 시점에, 스레드의 인터럽트 상태도 false 로 변경된다.

work 스레드는 이후에 자원을 정리하는 코드를 실행하는데, 이때 인터럽트의 상태는 false 이므로 인터럽트가 발생 하는 sleep() 과 같은 코드를 수행해도 인터럽트가 발생하지 않는다. 이후에 자원을 정상적으로 잘 정리하는 것을 확인 할 수 있다. 자바는 인터럽트 예외가 한 번 발생하면, 스레드의 인터럽트 상태를 다시 정상( false ) 으로 돌린다.

스레드의 인터럽트 상태를 정상으로 돌리지 않으면 이후에도 계속 인터럽트가 발생하게 된다. ** 인터럽트의 목적을 달성하면 인터럽트 상태를 다시 정상으로 돌려두어야 한다

728x90

'운영체제' 카테고리의 다른 글

Synchronized  (0) 2024.12.15
Volatile - 메모리가시성  (0) 2024.12.15
Thread - Join  (0) 2024.12.14
체크 예외 재정의  (1) 2024.11.29
Thread 생명 주기 - 코드  (0) 2024.11.29