화분

스레드의 코어 할당과 Yield() 본문

Study/JAVA

스레드의 코어 할당과 Yield()

ExcellEast 2024. 3. 10. 17:00

멀티스레딩을 공부하면서 스레드에 대한 코어 할당과 스레드의 yield() 메서드에 대한 궁금증이 생겨서 직접 여러가지 코드를 작성해보고 Gemini를 통해 알아낸 것들을 정리하고자 글을 썼다.

 

우선 yield()를 공부하기 위해 '이것이 자바다(개정판)'의 멀티스레드 파트에 적힌 예시 코드와 이것에 궁금한 점들을 해결하고자 추가적인 코드를 작성해가며 실험해보았다.

 

먼저 yield() 란? 

CPU 코어를 할당 받아 작업을 처리하던 스레드가 일을 안할때 해당 CPU 코어, 즉 코어를 할당 받은 커널 스레드를 다른 프로세스 내 스레드에게 양보하여 CPU의 효율을 끌어올리기 위한 메서드라고 생각하면 된다.

 

WorkThread.java

: Thread를 상속 받은 WorkThread 이다. 아래와 같이 if문의 조건이 false 상태이면 스레드의 yield() 메서드를 실행 한다.

package ch14.sec05.exam03;

public class WorkThread extends Thread{
    public boolean work = true;

    public WorkThread(String name){
        setName(name);
    }

    @Override
    public void run(){
        while(true){
            if(work){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {}
                System.out.println("--------------------------");
                System.out.println(getName() + ": 작업중... id : " +Thread.currentThread().getId());
            }else{
                Thread.yield();
            }
        }
    }
}

 

 

YieldExample.java

:테스트를 위한 코드 이다.

package ch14.sec05.exam03;

import java.awt.image.Kernel;

public class YieldExample {
    public static void main(String[] args) {
        System.out.println("[ Thread 생성 전 ] 사용하고 있거나 사용 가능한 모든 스레드의 개수 : " + Runtime.getRuntime().availableProcessors());
        System.out.println("[ Thread 생성 전 ] 현재 실행중인 모든 스레드의 개수 : " + Thread.activeCount());


        WorkThread workThreadA = new WorkThread("workThreadA");
        WorkThread workThreadB = new WorkThread("workThreadB");

        workThreadA.start();
        workThreadB.start();

        System.out.println(workThreadA.getName() + "[Thread 시작 후 ] 사용하고 있거나 사용 가능한 모든 스레드의 개수 : " + Runtime.getRuntime().availableProcessors());
        System.out.println(workThreadA.getName() + "[Thread 시작 후 ] 현재 실행중인 모든 스레드의 개수 : " + Thread.activeCount());

        try{Thread.sleep(5000);}catch(Exception e){}
        workThreadA.work = false;

        System.out.println(workThreadA.getName() + " - if문 false ] 사용하고 있거나 사용 가능한 모든 스레드의 개수 : " + Runtime.getRuntime().availableProcessors());
        System.out.println(workThreadA.getName() + " - if문 false ] 현재 실행중인 모든 스레드의 개수 : " + Thread.activeCount());
        try{Thread.sleep(10000);}catch(Exception e){}
        workThreadA.work = true;

        System.out.println(workThreadA.getName() + " - if문 true ] 사용하고 있거나 사용 가능한 모든 스레드의 개수 : " + Runtime.getRuntime().availableProcessors());
        System.out.println(workThreadA.getName() + " - if문 true ] 현재 실행중인 모든 스레드의 개수 : " + Thread.activeCount());

    }
}

 

 

테스트 결과

 

기대 했던 결과 1

 

Thread 생성 전 사용하고 있거나 사용 가능한 모든 스레드의 개수 : 6

Thread 생성 전 현재 실행중인 모든 스레드의 개수 : 1

Thread 실행 후 현재 실행 중인 모든 스레드의 개수 : 3

 

실제 결과 1 :

 

분석 : 현재 CPU의 코어 개수가 6개라 6개의 사용가능한 프로세서가 존재할 줄 알았는데 12개가 나왔다. Gemini에게 물어본 결과 하이퍼스레딩을 지원하는 CPU면 12개의 사용 가능한 프로세서가 존재할 수 있다고 한다. 

 

작업 스레드를 실행 하기 전에 Main 스레드 하나만 동작 할거라고 생각해서 1개의 스레드만 실행 중일거라고 생각했는데 2개란 결과가 나왔다. 이것은 GC(가비지 컬렉터)에게 스레드를 할당하였기 때문에 그렇다고 한다. 결국 프로그램을 시작하면 Main메서드에게 할당한 스레드와 GC에게 할당한 스레드, 총 2개의 스레드가 동작한다.

 

2개의 스레드를 실행 후에 실행 중인 스레드의 개수가 2개 늘어난 부분은 생각한 것과 맞아 떨어지는 예측이라고 본다.

 

기대 했던 결과 2 :

스레드 내 if문의 조건문이 false로 변경됨에 따라 yield() 메서드를 실행하면서 사용 중인 스레드의 개수에 변동이 있을거라 생각했다. 하지만...

 

if문의 조건이 false로 변경되었을 때 실행 중인 스레드의 개수와 실행 상태

 

위와 같이 변함이 없다. 내가 기대했던 바는 3개로 줄어들어야 하지 않을까? 였는데 실제론 차이가 없었다. 이것은 운영체제의 스레드 스케줄링 방식에 따라 결과가 달라질 수 있다고 한다. 내 생각엔 사용 가능한 여분의 스레드가 존재하기 때문에 굳이 스레드의 컨텍스트 스위칭을 하면서까지 사용하던 스레드의 수를 줄이거나 하진 않는거 같다.

 

 

 

다시 if문의 조건이 true로 바뀌었을때

 

 

결론.

1.처음 프로세스(프로그램)가 실행 되었을 때 Main 스레드와 GC(Garbage Collector) 스레드, 2개가 동작한다.

2.스레드가 yield() 메서드를 실행하여도 사용 중인 스레드의 개수는 변함이 없을 수 있다.