프로그래밍/Java

Java Virtual Thread (2), Thread와 Virtual Thread

개발정리 2024. 6. 22. 19:35

Thread

@Slf4j
public class Main {
    private static final Runnable runnable = new Runnable() {
        @Override
        public void run() {
            log.info("1) run. thread: {}", Thread.currentThread());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("2) run. thread: {}", Thread.currentThread());
        }
    };

    public static void main(String[] args) {
        log.info("1) main. thread: ", Thread.currentThread());

        // 일반 쓰레드 호출
        Thread thread = new Thread(runnable);
        thread.start();
    }
}
14:15:28.963 [main] INFO org.example.Main -- 1) main. thread: 
14:15:28.965 [Thread-0] INFO org.example.Main -- 1) run. thread: Thread[#20,Thread-0,5,main]
14:15:29.971 [Thread-0] INFO org.example.Main -- 2) run. thread: Thread[#20,Thread-0,5,main]

 

 

 

Virtual Thread

@Slf4j
public class Main {
    private static final Runnable runnable = new Runnable() {
        @Override
        public void run() {
            log.info("1) run. thread: {}", Thread.currentThread());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("2) run. thread: {}", Thread.currentThread());
        }
    };

    public static void main(String[] args) throws InterruptedException {
        log.info("1) main. thread: ", Thread.currentThread());

        Thread thread = Thread.ofVirtual().name("my Virtual").start(runnable);
        thread.join();
    }
}
14:19:18.058 [main] INFO org.example.Main -- 1) main. thread: 
14:19:18.064 [my Virtual] INFO org.example.Main -- 1) run. thread: VirtualThread[#20,my Virtual]/runnable@ForkJoinPool-1-worker-1
14:19:19.074 [my Virtual] INFO org.example.Main -- 2) run. thread: VirtualThread[#20,my Virtual]/runnable@ForkJoinPool-1-worker-1

 

만약, thread.join( )을 호출하지 않는다면 프로그램음 금방 죽는다. 

 

스레드는 일반 스레드와 데몬 스레드가 있다. ForkJoinPool는 데몬 스레드로 동작을 하고 있다. 자바의 경우 일반 스레드가 남아있으면 계속 실행이되고 데몬 스레드만 남아있으면 죽는다는 특징이 있다. thread.join( )는 데몬 스레드가 죽지 않기 위해 사용된다. 

 

일반 Thread를 사용할 시에도 thread.setDaemon(true)로 설정을 한 하여 Daemon Thread 사용 시 join이 없으면 바로 죽게된다.

 

 

thread.join( )

- 이 스레드가 종료될 때까지 기다f리며 이 메서드의 호출은 호출과 정확히 동일한 방식으로 동작한다.

 

 

 

로그 비교

Thread[#20,Thread-0,5,main]

VirtualThread[#20,my Virtual]/runnable@ForkJoinPool-1-worker-1

 

 

Thread는 Thread로 명시되어 로그가 찍히는 반면, VirtualThread는 VirtualThread라고 명시되고 ForkJoinPool이라는 플랫폼 스레드가 표시된다. 

 

VirtualThread는 플랫폼 스레드에 붙어서 실행이 된다는 것을 유추해 볼 수 있다.

 

 

 

VirtualThread가 하나만 필요한 경우

@Slf4j
public class VirtualThreadCreation {
    private static final Runnable runnable = new Runnable() {
        @Override
        public void run() {
            log.info("1) run. thread: {}", Thread.currentThread());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("2) run. thread: {}", Thread.currentThread());
        }
    };

    public static void main(String[] args) throws InterruptedException {
        log.info("1) main thread: " + Thread.currentThread());
        Thread thread = createVirtualThreadStarted();
        //Thread thread = createVirtualThreadUnstarted();
        thread.join();
        log.info("2) main. thread: " + Thread.currentThread());
    }

    private static Thread createVirtualThreadUnstarted() {
        Thread thread = Thread.ofVirtual().name("myVirtual1").unstarted(runnable);
        thread.start();
        return thread;
    }

    private static Thread createVirtualThreadStarted() {
        Thread thread = Thread.ofVirtual().name("myVirtual").start(runnable);
        return thread;
    }
}
19:07:58.615 [main] INFO org.example.VirtualThreadCreation -- 1) main thread: Thread[#1,main,5,main]
19:07:58.619 [myVirtual] INFO org.example.VirtualThreadCreation -- 1) run. thread: VirtualThread[#20,myVirtual]/runnable@ForkJoinPool-1-worker-1
19:07:59.628 [myVirtual] INFO org.example.VirtualThreadCreation -- 2) run. thread: VirtualThread[#20,myVirtual]/runnable@ForkJoinPool-1-worker-1
19:07:59.629 [main] INFO org.example.VirtualThreadCreation -- 2) main. thread: Thread[#1,main,5,main]

 

일반적으로는 스레드 풀처럼 만들어서 스레드를 여러개 호출한다. 위 코드는 여러 개의 스레드를 호출하는 것에는 불편함이 많다.