3. 스레드 제어와 생명 주기1
- 각 상태에 대해서 설명하시오

- New (새로운 상태): 스레드가 생성되었으나 아직 시작되지 않은 상태.
- Runnable (실행 가능 상태): 스레드가 실행 중이거나 실행될 준비가 된 상태.
- 일시 중지 상태들
- (Suspended States) Blocked (차단 상태): 스레드가 동기화 락을 기다리는 상태.
- Waiting (대기 상태): 스레드가 무기한으로 다른 스레드의 작업을 기다리는 상태.
- Timed Waiting (시간 제한 대기 상태): 스레드가 일정 시간 동안 다른 스레드의 작업을 기다리는 상태.
- Terminated (종료 상태): 스레드의 실행이 완료된 상태.
- Runnable 인터페이스의 run() 메서드를 구현할 때 InterruptedException 체크 예외를 밖으로 던질 수 없 는 이유는?
- 체크 예외
- 부모 메서드가 체크 예외를 던지지 않는 경우, 재정의된 자식 메서드도 체크 예외를 던질 수 없다.
-> Runnable의 run()이 throw가 없는 이유는 try catch로 예외 처리를 강제하기 위함 - 자식 메서드는 부모 메서드가 던질 수 있는 체크 예외의 하위 타입만 던질 수 있다.
- 부모 메서드가 체크 예외를 던지지 않는 경우, 재정의된 자식 메서드도 체크 예외를 던질 수 없다.
- 언체크(런타임) 예외
- 예외 처리를 강제하지 않으므로 상관없이 던질 수 있다.
- 체크 예외
- Join 함수를 어떤 경우에 사용하는가?
- join 함수는 특정 스레드가 완료될 때 까지 기다려야 하는 경우에 사용할 수 있다.
- sleep을 하거나 while()로 특정 스레드가 끝날 때 까지를 찾는 방법도 있겠지만 비효율적이기 때문에 join 함수를 통해서 특정 스레드가 완료됨을 간편하게 기다릴 수 있다.
- Join 함수를 사용하는 경우 join 함수를 호출하는 스레드와 join 함수 호출을 당하는 스레드의 스레드 상태 변화 플로우는 어떻게 되는가
- join 함수를 호출하는 스레드는 join 함수 호출 후 Runnable에서 Waiting 상태로 변하게 된다.
- join 함수 호출을 당하는 스레드는 Runnable에서 결국 Terminated가 된다.
- 그 이후 join 함수를 호출하는 스레드는 Waiting에서 다시 Runnable 상태로 변한다.
- join 함수의 단점은 무엇이며 그것을 보완하는 방안은 무엇인가?
- join 함수를 호출한 경우 특정 스레드가 종료될 때까지 무한정 기다려야한다는 단점이 있다.
- 따라서 join(ms)로 인자를 넣어서 호출하는 경우 특정 시간까지만 기다리고 그 이후에는 다시 Runnable로 변해서 처리를 이어갈 수 있다.
4. 스레드 제어와 생명 주기2
- 실행중인 특정 스레드를 멈추게 하고 싶을 때 flag를 지정 후 flag를 검사를 통해 스레드를 멈추게 할 수 있다. 이 방법의 단점은 무엇이며 이를 해결하기 위해 무엇을 도입할 수 있는가?
- flag를 지정해 검사를 하는 경우는 검사하는 해당 로직에서만 특정 스레드를 멈추게 할지 아닐지를 판단하게 되기 때문에 그 외의 작업시에는 멈추게 할 수가 없음.
- thread.interrupt() 함수를 호출하면 sleep과 같은 오래 걸리는 작업에 interrupt exception을 발생시켜 빠져나오게 함.
- 또한, flag로 작업을 진행할지 말지를 결정하지 않고 Thread.currentThread().isInterrupt()와 같은 방법으로 interrupt가 걸렸는지를 확인 할 수도 있다.
- 인터럽트를 확인하는 동시에 인터럽트가 true이면 false로 바꿔주는 함수가 무엇이며 이런 함수를 왜 사용하는가?
- Thread.interrupted()
- sleep 과 같은 함수가 없으면 interrupt를 받아도 interrupt가 발생하지 않으며, 원하지 않는 위치에서 interrupt가 발생할 수도 있다.
- 따라서 interrupted 함수로 interrupt를 받았는지 확인을 하고 바로 interrupt는 false로 돌려준다.
- 인터럽트는 왜 sleep과 같은 함수에서만 예외를 발생시킬까?
인터럽트는 sleep, wait, join과 같이 대기해야하는 함수에서 예외를 발생시킨다.- 인터럽트는 Waiting, Timed-Waiting 과 같은 상태에서 Interrupted Exception을 발생시켜 Runnable 상태로 깨워나게 해줌.
- Runnable, Blocked 상태에서는 Interrupted Exception을 발생시키지 않고 Interrupt flag만 true로 바꿔줌.
- 스레드의 무한 대기를 방지할 수 있고, 인터럽트 발생시 즉시 반응할 수 있게 하기 위해서.
- 따라서, sleep, wait, join과 같은 함수는 InterruptedException이라는 체크 예외가 강제되어 try ~ catch와 같은 구문으로 처리를 해줘야 함.
- 체크 예외는 IOException, SQLException, FileNotFoundException과 같이 외부 자원과 상호 작용 시 발생할 수 있는 문제로 개발자가 통제 할 수 없는 외부 요인에 대해 미리 강제로 처리하도록 함.
- 반대로 언체크드 예외는 NullPointerException, ArrayIndexOutOfBoundsException과 같은 예외들이 있음.
- yield 함수에 대해 설명하고 sleep 함수를 호출했을 때와 대비해서 Thread의 상태가 어떻게 변경되는가?
- yield 함수는 CPU 자원을 양보한다는 의미로 만약 스레드 큐에 실행되야 할 스레드가 있다면 그 스레드에게 지금 자신이 사용하고 있는 자원을 양보한다는 의미임.
- sleep 함수의 경우 스레드의 상태가 Runnable -> Waiting -> Runnable로 변하는 판면 yield 함수의 경우 스레드의 상태가 Runnable(start) -> Runnable(ready) -> Runnable(start)가 됨.
- 즉, yield의 경우에는 못해도 실행가능한 큐에 들어가므로 양보할 스레드가 없으면 바로 실행 됨.
- Runnable(ready)와 Waiting의 차이가 여기서 드러나는데 Runnable(ready)는 즉시 실행 가능한 큐에 들어가는 반면 Waiting은 기다림이 끝나고 나서 다시 Runnable(ready)로 들어가는 차이가 있음.
- 프린터기 에제에서 yield 함수는 어느 경우에 사용이 될 수 있나?
- 예를 들어 프린터 예제에서 프린터는 작업이 왔을 경우 작업물을 출력하기 때문에 작업이 왔는지를 무한정 체크하는 로직이 존재함.
- 작업이 왔는지를 무한정 체크하는 작업은 계속해서 CPU 자원을 소모하기 때문에 매우 자원 소모가 큰 작업임.
- 따라서, 할당된 작업이 없는 경우 yield 함수를 불러 다른 스레드에게 자원을 양보하고 나서 다시 할당받고 작업이 왔는지를 체크하는 방법이 자원 효율적임
'김영한의 실전 자바 - 고급 1편' 카테고리의 다른 글
| 김영한의 실전 자바 - 고급 1편(동시성 컬렉션) (0) | 2025.01.11 |
|---|---|
| 김영한의 실전 자바 - 고급 1편(CAS) (1) | 2025.01.11 |
| 김영한의 실전 자바 - 고급 1편(생산자 소비자 문제: Object - wait/notify, ReentarantLock - await/signal, BlockingQueue) (1) | 2025.01.08 |
| 김영한의 실전 자바 - 고급 1편(volatile, synchronized, LockSupport, ReentrantLock) (1) | 2025.01.05 |
| 김영한의 실전 자바 - 고급 1편(프로세스, 스레드) (3) | 2025.01.02 |