- [Java 정리] Thread 32022년 08월 19일
- starryeye
- 작성자
- 2022.08.19.:20
이미 알던 지식이지만, 기본으로 돌아가서.. Java의 관점에서 한번 정리해보자.
쓰레드의 실행 제어 메서드
쓰레드 상태를 다시 한번 보고 들어가자..
상태 설명 NEW 쓰레드가 생성되고 아직 start()가 호출되지 않은 상태 RUNNABLE 실행 중 또는 실행 가능한(실행 대기) 상태 BLOCKED 동기화 블럭에 의해 일시정지된 상태 (lock이 풀릴 때까지 기다리는 상태) WAITING 쓰레드의 작업이 종료되지는 않았지만 실행가능하지 않은 일시정지 상태이다. TIMED_WAITING WAITING와 동일하나 일시정지 시간이 지정된 경우의 일시정지 상태이다. TERMINATED 쓰레드의 작업이 종료된 상태 sleep()
일정 시간 동안 쓰레드를 멈추게 한다.
public static native void sleep(long millis) public static void sleep(long millis, int nanos)
1. sleep()에 의해 일시정지 상태가 된 쓰레드는 지정 시간이 다 되면, 잠에서 깨어나 실행 대기 상태가 된다.
2. 도중에 interrupt()가 호출되면 InterruptedException 예외가 발생하며, 잠에서 깨어나 실행 대기 상태가 된다.
3. 항상 현재 실행 중인 쓰레드에 대해 작동한다.
(A 쓰레드에서 B쓰레드의 참조변수 활용하여 sleep을 호출해도 호출한 A 쓰레드가 sleep된다.)
(-> static 메서드이지만, native 메서드로 호출한 쓰레드가 일시정지 상태가 됨)
(-> static 메서드니까 쓰레드 구분이 없을것 같은데? 라는 생각은 native 메서드로 row 레벨에서 구분된다고 이해)
4. InterruptedException은 체크 예외 이므로 try-catch 구문 혹은 throws를 해줘야한다.
예시
void delay(long millis) { try { Thread.sleep(millis); //Thread 클래스의 static 메서드인 sleep 호출 } catch(InterruptedException e) { //Interrupt()가 호출될 경우 } }
interrupt()와 interrupted(), isInterrupted()
public void interrupt() public static boolean interrupted() public boolean isInterrupted()
interrupt()는 쓰레드에게 작업을 멈추라고 요청한다.
- 쓰레드의 intterrupted 상태(인스턴스 변수)를 바꾼다.
interrupted()는 쓰레드의 interrupt()가 호출되었는지 알려준다.
- 호출되지 않았다면 false 반환
- 호출되었다면 true 반환, false로 다시 초기화
isInterrupted()는 쓰레드의 interrupt()가 호출되었는지 알려주지만, 다시 false로 초기화 하지 않는다.
(단순 현재의 interrupted 상태를 반환만 한다.)
쓰레드가 sleep(), wait(), join()에 의해 일시정지 상태(WAITING)에 있을 때, 해당 쓰레드에 대해
interrupt()를 호출하면, sleep(), wait(), join()에서 InterruptedException 예외가 발생하고
쓰레드는 실행 대기 상태(RUNNABLE)로 바뀐다.
(멈춰있던 쓰레드를 깨워서 실행가능한 상태로 만드는 것)
예시
Thread th = new Thread(); th.start(); ... th.interrupt(); class MyThread extends Thread { public void run() { while(!interrupted()) { ... //인터럽트 발생 전까지 계속 돈다. } } }
suspend(), resume(), stop()
suspend()는 sleep()처럼 쓰레드를 일시정지 상태로 만든다.
resume()은 suspend()에 의해 일시정지된 쓰레드를 다시 실행대기 상태로 변경 시킨다.
stop()은 호출되는 즉시 쓰레드가 종료된다.
Java API문서에 위 세가지의 메서드는 모두 Deprecated이다.
쓰레드의 실행을 제어하기 쉬운 메서드이지만, 교착상태를 유발하기 좋은 메서드이므로 사용을 권장하지 않는다.
yield()
yield()는 쓰레드 자신에게 주어진 실행시간을 다음 차례의 쓰레드에게 양보한다.
(yield()와 interrupt()를 적절히 사용하면, 프로그램의 응답성을 높이고 효율적인 실행이 가능해진다.)
public static native void yield()
예시
//class MyThread implements Runnable Thread th; boolean checked = true; public MyThread(String name) { th = new Thread(this, name); // Thread(Runnable r, String name) } public void check() { checked = false; //Thread.currentThread().interrupt(); 이렇게 하면 호출한 쓰레드가 interrupt th.interrupt(); } public void run() { while(true) { if(checked) { try { Thread.sleep(10000); } catch(InterruptedException e) {} }else { Thread.yield(); } } }
해당 쓰레드 동작 로직은 while문을 끊임 없이 도는 것이다.
checked라는 인스턴스 변수가 true라면 sleep()을 수행하고 false라면 yield() 메서드를 호출한다.
1. 여기서..
else 부분이 없다고 생각해보자..
checked 인스턴수 변수가 false라면 아무 의미 없이 while 구문을 돌 것이다...
이런 상태를 바쁜 대기상태(busy-waiting)라고 한다.
이는 좋지 않은 코드이며, 위 코드처럼 else로 yeild() 메서드를 호출해주도록 하자..
남은 실행시간을 while문에서 낭비하지 않고 다른 쓰레드에게 양보(yeild) 해주도록 하자.
-> 응답성 향상
2. check()라는 메서드가 호출되면 interrupt() 메서드를 호출해주는 이유는...
쓰레드가 sleep이 호출되어 일시정지 상태에 있을 때,
interrupt()메서드로 인해 InterruptedException 예외가 호출 될 것이고..
바로 yield가 호출 될 것이다.
-> 응답성 향상
(interrupt()가 없다면 sleep이 다끝나고, 실행대기시간을 기다린후.. yield가 호출 될 것이다..)
<참고>
코어 수 보다 많은 멀티쓰레드 환경에서 sleep은 일시정지 상태기 때문에 일시정지 상태일때
다른 쓰레드가 RUNNABLE로 수행되고 있을 것이다..
그래서 다른쓰레드 수행되니까 yield의 의미가 없다고 생각하지말고..
sleep이 아닌 다른 로직을 계속 돌려서..
(그러면 해당 로직에서 InterruptedException 처리 말고 다르게 처리가 필요하긴함)
RUNNABLE상태에서 점유 한다고 생각하자..
-> yield()를 호출해주는게 의미가 있다
join()
쓰레드 자신이 하던 작업을 잠시 멈추고 다른 쓰레드가 지정된 시간동안 작업을 수행하도록 할 때 사용한다.
쓰레드 자신은 다른 쓰레드가 작업을 끝낼때까지 기다림.
보통 쓰레드 A가 특정 작업을 하기전에 B쓰레드가 뭔가를 해줘야 특정 작업을 할 수 있을 때..
B.join()을 불러준다.
B가 일시정지 상태에 있을 수도 있으니.. join() 전에 interrupt()도 불러준다..
'Java' 카테고리의 다른 글
[Java 정리] Thread 5 (0) 2022.08.22 [Java 정리] Thread 4 (0) 2022.08.22 [Java 정리] Thread 2 (0) 2022.08.13 [Java 정리] Thread 1 (0) 2022.08.13 [Java 정리] String, final, Immutable (0) 2022.08.05 다음글이전글이전 글이 없습니다.댓글