[Java] 스레드 제어

Devlog·2024년 4월 1일

Java

목록 보기
35/41

: 스레드 객체를 생성하고 start() 메소드를 호출하면
바로 실행되는 것이 아니라 실행 대기 상태가 됨

: 실행대기 상태란 언제든지 실행할 준비가 되어 있는 상태를 말함

: 운영체제는 실행 대기 상태에 있는
스레드 중에서 하나를 선택해서 실행 상태로 만듦

: 실행 상태의 스레드는 run() 메소드를 모두 실행하기 전에
다시 실행 대기 상태로 돌아갈 수 있으며,
실행 대기 상태에 있는 다른 스레드가 선택되어 실행 상태가 되기도 함

: 실행 상태에서 run() 메소드의 내용이 모두 실행되면
스레드의 실행이 멈추고 종료 상태가 됨


✔️ 스레드 상태

- 실행 상태
: 실행 대기 상태에 있는 스레드 중에서
운영체제는 하나의 스레드를 선택하고 CPU(코어)가
run() 메소드를 실행하도록 함

: 실행 상태의 스레드는 run() 메소드를
모두 실행하기 전에 다시 실행 대기 상태로 돌아갈 수 있음

: 스레드는 실행 대기 상태와 실행 상태를 번갈아가며
자신의 run() 메소드를 조금씨 실행함

- 종료 상태
: 실행 상태에서 run() 메소드가 종료되면,
더 이상 실행할 코드가 없기 때문에
스레드의 실행은 멈추게 됨

→ 이처럼 스레드는
실행 대기상태와 실행 상태로 번갈아 변하면서,
경우데 따라 실행 상태에서 일시 정지 상태로 가기도 함

일시 정지 상태는 스레드가 실행할 수 없는 상태를 말함

일시 정지 상태에서는 바로 실행 상태로 돌아갈 수 없고,
일시 정지 상태에서 빠져나와 실행 대기 상태로 가야함


✔️ 스레드 상태 제어

- 스레드 상태 제어
: 실행 중인 스레드의 상태를 변경하는 것

ex)
사용자는 미디어 플레이어에서
동영상을 보다가 일시 정지할 수도 있고,
종료할 수도 있음

일시 정지는 조금 후 다시 동영상을 보겠다는 의미이므로
미디어 플레이어는 동영상 스레드를 일시 정지 상태로 만들어야함

그리고 종료는 더 이상 동영상을 보지 않겠다는 의미로
미디어 플레이어는 스레드를 종료 상태로 만들어야함

: 스레드 상태 제어는 주어진 시간 동안
일시 정지시키는 sleep() 메소드와 스레드를
안전하게 종료 시키는 stop 플래스,
interrupt() 메소드를 사용함

→ 취소선으로 표시한 메소드는 스레드의 안전성을 해친다고 하여 더 이상 사용하지 않도록 권장된 Deprecated 메소드 임

- 상태 변화를 가져오는 메소드의 종류


✔️ 주어진 시간 동안 일시 정지

try {
	Thread.sleep(1000);
} catch(InterruptedException e) {
	//interrupt() 메소드가 호출되면 실행
}

: 실행 중인 스레드를 일정 시간 멈추게 하고 싶다면
Thread 클래스의 정적 메소드인 sleep()을 사용하면 됨

: Thread.sleep() 메소드를 호출한 스레드는
주어진 시간 동안 일시 정지 상태가 되고,
다시 실행 대기 상태로 돌아감

: 매개값에는 얼마 동안 일시 정지 상태로 있을 것인지
밀리세컨드(1/1000초) 단위로 시간을 주면 됨

: 일시 정지 상태에서 주어진 시간이 되기 전에
interrupt() 메소드가 호출되면
InterruptedException이 발생하기 때문에
예외 처리가 필요함

 👩‍💻3초 주기로 10번 비프음 발생
import java.awt.Toolkit;

public class SleepExample {
	public static void main(String[] args) {
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		for(int i=0; i<10; i++) {
			toolkit.beep();
			try {
				// 3초 동안 메인 스레드를
				// 일시 정지 상태로 만듦
				Thread.sleep(3000);
			} catch(InterruptedException e) {}
		}
	}
}

✔️ 스레드의 안전한 종료

: 스레드는 자신의 run() 메소드가 모두 실행되면
자동적으로 종료됨

: 하지만 경우에 따라 실행 중인 스레드를
즉시 종료해야 할 때가 있음

ex) 동영상을 끝까지 보지 않고,
사용자가 멈춤을 요구할 때

: Thread는 스레드를 즉시 종료하기 위해서
stop() 메소드를 제공하고 있는데,
이 메소드는 deprecated(중요도가 떨어져
이제 사용되지 않음) 되었습니다.
→ 그 이유는 stop() 메소드로 스레드를
갑자기 종료하게 되면 스레드가 사용 중이던
자원들이 불안전한 상태로 남겨지기 때문

- 안전하게 종료하는 방법
1) stop 플래그를 이용하는 방법
: 스레드는 run()메소드가 끝나면 자동적으로 종료되므로,
run() 메소드가 정상적으로 종료되도록 유도하는 것이 중요함

public class XXXThread extends Thread {
	//stop 플래그 필드
	private boolean stop;

	public void run() {
		// stop이 true가 되면 run()이 종료
		while( !stop ) {
			스레드가 반복 실행하는 코드;
		}
		// 스레드가 사용한 자원 정리
	}
}

: stop 필드가 false일 경우에는
while문의 조건식이 true가 되어 반복 실행하지만,

stop 필드가 true일 경우에는 
while문의 조건식이 false가 되어 while문으로 빠져나옴

그리고 스레드가 사용한 자원을 정리하고,
run() 메소드가 끝나게 됨으로써 스레드는 안전하게 종료함
 👩‍💻무한 반복해서 출력하는 스레드
public class PrintThread1 extends Thread { 
	private boolean stop;
	
	public void setStop(boolean stop) {
		this.stop = stop;
	}
	
	public void run() {
		while(!stop) {
			System.out.println("실행 중");
		}
		//stop이 true가 될때 
		System.out.println("자원 정리");
		System.out.println("실행 종료");
	}
}

👩‍💻 1초 후 출력 스레드를 중지
public class StopFlagExample {
	public static void main(String[] args) {
		PrintThread1 printThread = new PrintThread1();
		printThread.start();
		
		try { Thread.sleep(1000); }
		catch(InterruptedException e) {}
		
		// 스레드를 종료하기 위해
		// stop 필드롤 true로 변경
		printThread.setStop(true);
	}
}

2) interrupt() 메소드를 이용하는 방법
: interrupt() 메소드는 스레드가 일시 정지 상태에 있을 때
InterruptedException을 발생시키는 역할을 함

이를 이용하면 run() 메소드를 정상 종료할 수 있음

👩‍💻 1초 후 출력 스레드를 중지
public class PrintThread2 extends Thread {
	public void run() {
		try {
			while(true) {
				System.out.println("실행 중");
				Thread.sleep(1);
			}
		} // Thread.sleep(1)에서 
		// InterruptedException 발생시 예외처리 이동  
		catch(InterruptedException e) {}
		
		System.out.println("자원 정리");
		System.out.println("실행 종료");
	}
}

👩‍💻 무한 반복해서 출력하는 스레드
public class StopFlagExample {
	public static void main(String[] args) {		
		Thread thread = new PrintThread2();
		thread.start();
		
		try { Thread.sleep(1000); }
		catch(InterruptedException e) {}
		
		// 스레드를 종료하기 위해
		// InterruptedException을 발생시킴
		thread.interrupt();
	}
}

→ 스레드가 실행 대기 또는 실행 상태에 있을 때
interrupt() 메소드가 실행되면
즉시 InterruptedException이 발생한다는 것

따라서 스레드가 일시 정지 상태가 되지 않으면
interrupt() 메소드 호출은 아무런 의미가 없음

그래서 짧읍 시간이나마 일시 정지시키기 위해
Thread.sleep(1)을 사용한 것

- 일시 정지를 만들지 않고도 interrupt()의 호출 여부를 알 수 있는 방법

boolean status = Thread.interrupted();
boolean status = objThread.isInterrupted();

: interrupt() 메소드가 호출되었다면
스레드의 interrupted()와 isInterrupted() 메소드는
true를 리턴함

interrupted()는 정적 메소드로 현재 스레드가
interrupted 되었는지 확인하는 것이고,

isInterrupted()는 인스턴스 메소드로 현재 스레드가
interrupted 되었는지 확인함

👩‍💻 Thread.sleep(1)을 사용하지 않고,
Thread.interrupted()를 사용해서
PrintThreadinterrupt()가 호출되었는지 확인한 다음
while문 빠져나가기

public class PrintThread2 extends Thread {
	
	public void run() {

		while(true) {
			System.out.println("실행 중");
			
			if(Thread.interrupted()) {
				break;
			}
		}
		
		
		System.out.println("자원 정리");
		System.out.println("실행 종료");
	}
}

0개의 댓글