[CS/운영체제] 멀티스레드와 동시성 - 6부

황제연·2025년 6월 29일
0

CS학습

목록 보기
120/193
post-thumbnail

yield

특정 스레드를 얼마나 실행할지는 운영체제의 스케줄링을 통해 결정됩니다
이때, 특정 스레드가 바쁘지 않은 상황이라 다른 스레드에게 CPU 실행 기회를 양보하고 싶을 수 있습니다

양보를 통해서 스케줄링 큐에 대기중인 다른 스레드가 CPU 실행 기회를 더 빨리 얻을 수 있습니다

운영체제의 스케줄링 방식

public class Main {
	static fian int THREAD_COUNT = 10000;

	public static void main(String[] args){
		for(int i=0; i<THREAD_COUNT; i++){
			Thread thread = new Thread(new MyTest());
			thread.start();
		}
	}

	static class MyTest implements Runnable{
		public void run(){
			for(int i=0; i<20; i++){
				System.out.println(Thread.currentThread(). getName() + " : " + i);
			}
		}
	}


}

위와같이 1만개의 스레드를 실행하고, 스레드마다 0~19까지 출력하면 끝나는 로직이 있습니다

어떠한 추가로직 없이 단순히 위와같이 돌리면 운영체제의 스레드 스케줄링을 따릅니다
운영체제의 스케줄링 정책과 환경에 따라 출력 순서가 달라집니다

sleep()을 사용하는 방식

public class Main {
	static fian int THREAD_COUNT = 10000;

	public static void main(String[] args){
		for(int i=0; i<THREAD_COUNT; i++){
			Thread thread = new Thread(new MyTest());
			thread.start();
		}
	}

	static class MyTest implements Runnable{
		public void run(){
			for(int i=0; i<20; i++){
				System.out.println(Thread.currentThread(). getName() + " : " + i);
				sleep(2);
			}
		}
	}


}

이번에는 sleep(2)를 사용하는 방법입니다
이 경우는 스레드 상태를 2ms동안 RUNNABLE -> TIME_WAITING 상태로 변경합니다
이렇게하면 스레드는 CPU를 사용하지 않고 실행 스케줄리에서 제외됩니다

그리고 2ms가 지나면 다시 TIME_WAITING -> RUNNABLE 상태가 되면서 실행 스케줄링에 포함됩니다
이렇게 하면 TIMED_WAITING 상태가 되면서 다른 스레드에 CPU 실행을 양보하게 되고
스케줄링 큐에 대기중인 다른 스레드가 CPU 실행 기회를 더 빨리 얻을 수 있씁니다

단점

하지만 RUNNABLE -> TIME_WAITING -> RUNNABLE로 변경되는 과정이 복잡하며,
특정 시간만큼 스레드가 실행되지 않는 단점이 있습니다

만약 양보할 스레드가 없다면 내 스레드를 더 실행하는 것이 나을 수도 있는데,
이 상황은 2ms의 쉬는 시간이 반드시 포함됩니다.
즉, 양보할 스레드가 없는데도 양보하는 이상한 상황이 발생합니다

yield()

public class Main {
	static fian int THREAD_COUNT = 10000;

	public static void main(String[] args){
		for(int i=0; i<THREAD_COUNT; i++){
			Thread thread = new Thread(new MyTest());
			thread.start();
		}
	}

	static class MyTest implements Runnable{
		public void run(){
			for(int i=0; i<20; i++){
				System.out.println(Thread.currentThread(). getName() + " : " + i);
				Thread.yield();
			}
		}
	}


}

자바의 스레드는 RUNNABLE 상태일 때,
운영체제의 스케줄링은 다음과 같은 상태를 가질 수 있습니다

  • Running: 스레드가 CPU에서 실제 실행중입니다
  • Ready: 스레드가 실행될 준비가 되었지만 CPU가 바빠서 스케줄링 큐에서 대기중입니다

운영체제는 실행상태의 스레드를 잠깐 실행하고 다시 Ready 상태로 만듭니다
Ready 상태의 스레드들은 잠깐 Running 상태로 변경해서 실행합니다

이 과정을 반복하는데 자바는 두 상태를 구분할 수는 없습니다

yield() 동작방식

Thread.yield()를 사용하면 현재 실행중인 스레드가 자발적으로 CPU 실행을 양보해서
다른 스레드가 실행할 수 있도록 합니다

yield() 메소드를 호출한 스레드는 RUNNABLE 상태를 유지하면서 CPU를 양보합니다
즉, 스레드가 다시 스케줄링 큐에 들어가면서 다른 스레드에게 CPU 사용 기회를 양보합니다

자바에서 Thread.yield()는 현재 실행중인 스레드가 CPU를 양보하도록 힌트를 줍니다
이것은 스레드가 자신에게 할당된 실행시간을 포기하고 다른 스레드가 실행할 수 있는 기회를 줍니다
참고로 힌트는 힌트일 뿐, 강제적인 실행순서를 지정하지 않으며 반드시 다른 스레드가 실행되지는 않습니다

또한 yield()는 RUNNABLE 상태를 유지하기 때문에,
양보할 스레드가 없다면 본인 스레드를 계속 실행할 수 있습니다

참고

  • 김영한의 실전 자바 - 고급 1편
profile
Software Developer

0개의 댓글