효율적인 멀티스레드 프로그래밍을 위해서는 정교한 스케줄링을 통해 프로세스에게 주어진 자원과 시간을 여러 스레드가 낭비 없이 잘 사용하도록 해야 한다.
스레드 상태
스레드의 생성과 소멸 과정
- 스레드를 생성하고 start()를 호출하면 바로 실행되는 것이 아니라 실행대기열에 저장되어 자신의 차례가 될 때까지 기다리고, 실행대기열은 Queue와 같은 구조로 먼저 실행대기열에 들어온 스레드부터 실행한다.
- 실행대기상태에 있다가 자신의 차례가 되면 실행상태가 된다.
- 주어진 실행시간이 다되거나 yield()를 만나면 다시 실행대기상태가 되고 다음 차례의 스레드가 실행상태가 된다.
- 실행 중에 suspend(), sleep(), wait(), join(), I/O block에 의해 일시정지 상태가 될 수 있다.
- 지정된 일시정지시간이 다되거나(time-out), notify(), resume(), interrupt()가 호출되면 일시정지상태를 벗어나 다시 실행대기열에 저장되어 자신의 차례를 기다린다.
- 실행을 모두 마치거나 stop()이 호출되면 스레드는 소멸한다.
스레드 스케줄링 메서드
sleep(long millis)
- 일정시간 동안 스레드를 멈추게 한다.
static void sleep(long millis) // -> 1/1000 초 단위
static void sleep(long millis, int nanos) // -> 1/1000 초 단위 + 나노초
// Example
try {
Thread.sleep(1, 500000); // 쓰레드를 0.0015초 동안 멈춤
} catch(InterruptedException e) { ... } // 예외처리를 해주어야 프로그램이 멈추지 않는다.
sleep()에 의해 일시정지 상태가 된 스레드는 지정된 시간이 다 되거나 interrupt()가 호출되면(InterruptedException 발생), 잠에서 깨어나 실행대기 상태가 된다.
interrupt()와 interrupted()
- 쓰레드의 작업을 취소한다.
- 대기(Waiting) 상태인 스레드를 실행대기(Runnable) 상태로 만든다.
진행 중인 스레드의 작업이 끝나기 전에 취소시켜야 할 때가 있다. 그때 interrupt() 메서드를 이용하여 스레드에게 작업을 멈추라고 요청한다. 하지만 단지 멈추라고 요청만 하는 것일 뿐 스레드를 강제로 종료시키지 못한다.
interrupt() 메서드는 그저 스레드의 interrupted 상태(인스턴스 변수)를 바꾸는 것일 뿐이다.
interrupted() 메서드는 인스턴스 변수의 값을 읽어와 리턴하는 변수다.
Thread th = new Thread();
th.start();
th.interrupt();
class MyThread extends Thread {
public void run() {
while(!interrupted()) {
...
}
}
}
// Thread 클래스 interrupted 관련 예시
class Thread {
boolean interrupted = false; // 인스턴스 변수
...
boolean isInterrupted() {
return interrupted;
}
boolean interrupt() {
interrupted = true;
}
}
suspend(), resume(), stop()
- suspend() 메서드는 sleep()처럼 스레드를 멈추게 한다.
- suspend() 메서드를 통해 멈춘 쓰레드는 resume() 메서드를 이용해 다시 실행대기 상태로 만들 수 있다.
- stop() 메서드로 호출하면 즉시 쓰레드가 종료된다.
하지만 suspend()와 stop() 메서드는 교착상태(Deadlock)를 만들 우려가 있어 사용에 권장되지 않는다.(현재 Deprecated 상태)
yield()
- 자신의 실행시간의 남은 시간을 다음 쓰레드에게 양보하고, 자신(현재 스레드)은 실행대기한다.
- yield()와 interrupt()를 적절히 사용하면, 응답성과 효율을 높일 수 있다.
예시 사진을 보면 suspend() 메서드를 이용해 스레드에 신호를 주어 실행대기 상태의 스레드를 다시 수행할 수 있게 한다.
join()
- 지정된 시간동안 특정 스레드가 작업하는 것을 기다린다.
- 예외처리를 해야 한다. InterruptedException 예외가 발생하면 작업을 다시 시작한다.
스레드 자신이 하던 작업을 잠시 멈추고 다른 스레드가 지정된 시간 동안 작업을 수행하도록 할 때 join()을 사용한다.
join() 또한 sleep()처럼 interrupt()에 의해 대기 상태에서 벗어날 수 있다.
'Java > 기초' 카테고리의 다른 글
[Java 기초] Generics(제네릭) (0) | 2023.06.02 |
---|---|
[Java 기초] 컬렉션 프레임워크 (Collections Frmaework) (0) | 2023.05.26 |
[Java 기초] 정규식(Regular Expression) regex 패키지 (0) | 2023.05.20 |
[Java 기초] Random 클래스 (0) | 2023.05.20 |
[Java 기초] Objects 클래스 (0) | 2023.05.19 |