강의 메모 - 스레드 생명주기와 상태 #
개요 #
- 자바 스레드는 생성, 실행, 종료에 따른 상태를 가지고있다. OS 스레드 상태를 의미하지 않는다.
- 자바 스레드는 어떤 시점이던 6가지 상태 중 오직 1개의 상태를 가질 수 있다.
- 자바 스레드의 현재 상태를 가져오려면 Thread의 getState() 메서드를 사용하여 가져올 수 있다.
- Thread 클래스에는 스레드 상태에 대한 ENUM 상수를 정의하는 Thread.State 클래스를 제공한다.
스레드 상태 #
- NEW : 객체만 생성된 상태
- RUNNABLE
- WAITING : 대기는 언제하는가? 대표적으로 쓰레드가 CPU에서 할당받아서 실행하다가, I/O 입출력 관련 작업이 발생되어 CPU를 사용하지 않는 대기 상태
- TIMED_WAITING : 대기 시간이 지정된 상태
- BLOCKED : 락(lock) : 쓰레드가 여러개일때 공유 데이터 접근시 여러 문제가 발생하는데, 동시에 접근하지 못하도록 막는것
- TERMINATED
스레드 생명주기 #
Running 상태 - 스레드에는 없는 상태정보, 전체 생명주기 흐름을 이해하기 위해 실행중인 상태로 표시한것일 뿐, Runnable 상태에 해당한다.
-
객체 생성 상태 스레드 객체는 생성되었지만 아직 start() 하지 않은 상태 JVM에는 객체가 존재하지만 아직 커널로의 실행은 안된 상태
-
Runnable start()를 실행하면 내부적으로 커널로의 실행이 일어나고 커널 스레드로 1:1 매핑된다. 스레드는 바로 실행 상태가 아닌 언제든지 실행할 준비가 되어있는 실행 가능한 상태가 된다. 스레드가 실행 상태로 전환하기 위해서는 현재 스레드가 어떤 상태로 존재하든지, 반드시 실행 대기 상태를 거쳐야한다.
-
스케줄링 실행 가능한 상태의 스레드에게 실행할 시간을 제공하는 것은 OS 스케줄러의 책임이다 스케줄러는 멀티 스레드 환경에서 각 스레드에게 고정된 시간을 할당해서 실행 상태와 실행 가능한 상태를 오가도록 스케줄링한다 (스레드가 여러개있을때 스레드마다 번갈아가면서 CPU 할당 시간을 고정해서 그만큼 수행한다)
-
실행상태 스레드는 스케줄러에 의해 스케줄링이 되면 실행 상태로 전환되고, CPU를 할당받아 run() 메서드를 실행한다. 스레드는 아주 짧은 시간동안 실행된 다음 스레드가 실행될 수 있도록 CPU를 일시 중지하고 다른 스레드에 양도하게된다 (컨텍스트 스위칭) 실행 상태에서 생성과 종료 상태를 제외한 다른 상태로 전환될 때 스레드 혹은 프로세스간 컨텍스트 스위칭이 일어난다고 할 수 있다.
-
실행상태 -> 실행 대기 상태 실행 상태에서 스레드의 yield() 메서드를 호출하거나 운영체제 스케줄러에 의해 CPU 실행을 일시 중지하는 경우 실행 가능한 상태로 전환한다.
-
실행 상태로 전환
-
일시 정지 상태 (지정된 시간이 있는 경우 - Timed Waiting) 스레드는 sleep 및 time-out 매개변수가 있는 메서드를 호출할때 시간이 지정된 대기 상태가 된다 스레드의 대기 시간이 길어지고 CPU의 할당을 계속 받지 못하는 상황이 발생하면 기아 상태가 발생하게 되는데 이 상황을 피할 수 있다.
-
실행 대기 상태 스레드가 대기 상태의 지정 시간이 완료되거나 다른 스레드에 의해 인터럽트가 발생하거나 대기가 해제되도록 통지를 받게되면 실행 대기 상태가 된다.
-
임계 영역 동시적 접근 멀티 스레드 환경에서 각 스레드가 동기화된 임계 영역에 접근을 시도 (Critical Section 접근 시도 : 임계영역; 오직 하나의 쓰레드가 접근할 수 있도록 처리된 영역)
-
일시 정지 상태 (차단됨 - Blocked) 스레드가 동기화된 임계 영역에 접근을 시도하다가 Lock을 획득하지 못해서 차단된 상태 스레드는 Lock을 획득할 때까지 대기한다.
-
일시 정지 상태 -> 실행 대기 상태 스레드가 Lock을 획득하게 되면 실행 대기 상태가 된다.
-
실행 상태로 전환 실행 대기상태에서 가능
-
일시 정지 상태 (Waiting 상태) 스레드가 실행 상태에서 다른 스레드가 특정 작업을 수행하기를 기다리는 상태 (자기 스스로 빠져나오지못함) wait()은 다른 스레드에 의해 notify() 받을때까지, join()은 스레드의 실행이 종료되거나 인터럽트가 발생할때까지 대기한다. joing() : 쓰레드A, 쓰레드B가 있을때 쓰레드 A에서 B.joing() 실행하면 쓰레드B의 모든 작업(run 메서드 내부) 이 모두 완료될때까지 대기하는것
-
일시 정지 상태 -> 실행 대기 상태 wait 상태의 쓰레드가 다른 쓰레드에 의해 notify() 혹은 notifyAll()이 일어나면 실행 대기 상태가 된다 다른 스레드에 의해 인터럽트가 발생할 경우 실행 대기 상태로 전환한다
-
실행 상태로 전환
-
실행 종료 상태 실행이 완료되었거나 오류 또는 처리되지않은 예외와 같이 비정상적으로 종료된 상태 종료된 스레드는 종료되어 더이상 사용할 수 없다
정리 #
스레드 생명주기와 상태를 잘 알아야, 스레드를 효과적으로 잘 운용할 수 있다.
- 스레드는 어떤 상황, 시점, 조건에 의해 상태 전이가 일어나는가?
- 스레드의 API를 사용함에 있어 해당 API가 어떤 상태를 일으키며 스레드간 영향을 미치게 되는가? 스레드의 실행 관점에서 보면 출발지가 스레드의 start() 메서드 실행이라면 목적지는 스레드의 run() 메서드 실행이 된다는 점이다.