Programming

Java 21 new feature: Virtual Threads #RoadTo21 정리

nahud 2024. 11. 6. 02:13

Java 21 new feature: Virtual Threads #RoadTo21

위 유튜브 영상을 기반으로 정리한 내용이다.

 

Java 21의 새로운 기능: 가상 스레드 (Virtual Threads)

Java 21에서 도입된 가상 스레드는 고성능 멀티스레딩 환경을 구현하기 위한 획기적인 기능이다. 가상 스레드는 전통적인 커널 기반 스레드와 달리 가볍고, 대규모 병렬 작업을 효과적으로 지원한다. 이 글에서는 가상 스레드가 필요한 이유, 기본 동작 방식, 성능 상의 장점과 한계를 설명한다.

 

1. 왜 가상 스레드가 필요한가?

기존의 스레드 모델에서는 플랫폼 스레드가 사용되었으며, 이러한 스레드는 커널 스레드를 기반으로 동작한다. 플랫폼 스레드의 문제는 메모리 사용과 생성 비용이 높다는 것이다. 스레드 하나가 2MB 이상의 메모리를 필요로 하기 때문에, 대규모 병렬 처리를 위해 많은 스레드를 생성하면 메모리 부담이 커지고 성능에 악영향을 준다.

CPU와 스레드 효율성 문제

Java 애플리케이션에서 데이터베이스 요청이나 네트워크 호출을 사용할 때 CPU는 주로 유휴 상태에 놓인다. 기존의 비동기 처리는 스레드를 차단하지 않기 위해 동시성 프레임워크를 사용하지만, 코드 복잡성과 디버깅 어려움이라는 문제점이 따른다. 이를 해결하기 위해 Java 21은 가벼운 가상 스레드를 도입하여 비용 부담을 줄이고 성능을 극대화하려 했다.

2. 가상 스레드의 동작 방식

가상 스레드는 커널 스레드의 '감싸기'형태로 작동하며, 각 플랫폼 스레드 위에서 여러 가상 스레드가 실행된다. 이를 통해 많은 작업이 동시에 처리되더라도 효율적인 CPU 사용이 가능하다.

  • 언마운트 방식: 가상 스레드는 I/O와 같은 블로킹 작업을 감지하면 플랫폼 스레드에서 언마운트되어 메모리의 다른 위치(힙 메모리)로 스택을 옮겨 리소스를 효율적으로 관리한다.
  • 작업 재개: 가상 스레드의 블로킹 작업이 끝나면 다시 플랫폼 스레드에 마운트되어 작업을 이어서 수행한다. 이는 Java의 `Continuation` API를 통해 이루어지며, 모든 블로킹 작업은 `Continuation.yield` 메서드를 호출해 스레드를 언마운트한다.

3. 가상 스레드의 장점

가상 스레드는 기존의 플랫폼 스레드보다 훨씬 가볍고 유연하여, 큰 메모리 비용 없이도 다수의 스레드를 실행할 수 있다.

  • 높은 효율성: 가상 스레드는 대량의 스레드를 빠르게 생성하고 삭제할 수 있다. 덕분에 Java 애플리케이션은 메모리 관리 측면에서 큰 개선을 경험하게 된다.
  • 블로킹 작업 최적화: 가상 스레드는 블로킹 작업에 최적화되어, 비동기 코드로 전환하지 않고도 높은 성능을 유지할 수 있다.
  • 스레드 풀 필요 없음: 기존 플랫폼 스레드처럼 스레드 풀을 유지할 필요가 없으며, 필요 시 생성하고 작업이 끝나면 자동으로 소멸시킬 수 있다.

4. 가상 스레드의 사용 예제

Java 21에서는 가상 스레드를 쉽게 생성하고 사용할 수 있도록 `Thread.ofVirtual` 메서드를 제공한다. 예를 들어, `Executors.newVirtualThreadPerTaskExecutor()` 를 통해 가상 스레드를 자동으로 생성하고 관리할 수 있다.

ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
executor.submit(() -> {
    // 블로킹 I/O 작업
});

이렇게 생성된 가상 스레드는 매우 가벼워서 메모리와 CPU 자원을 효율적으로 활용할 수 있다.

5. 가상 스레드 사용 시 주의 사항

가상 스레드는 성능 향상을 제공하지만 모든 작업에 적합한 것은 아니다. 몇 가지 주의할 점은 다음과 같다.

  • 비동기 작업에 적합하지 않음: 가상 스레드는 주로 블로킹 I/O 작업에 최적화되어 있으며, 순수 메모리 계산 작업(CPU집약적인)에는 적합하지 않다. 이러한 작업에서는 기존 플랫폼 스레드가 더 적합하다.
  • 네이티브 코드 호출: 가상 스레드가 네이티브 코드(C/C++)와 상호 작용할 때는 플랫폼 스레드에 고정되어 이동하지 않는다.
  • 동기화 블록의 한계: `synchronized` 블록 안에서 가상 스레드를 사용할 경우, 스레드는 다시 플랫폼 스레드에 고정된다. 성능이 저하될 수 있으므로, 장시간의 블로킹이 예상되는 작업에서는 `ReentrantLock` 으로 대체하는 것이 좋다.

6. 결론

가상 스레드는 Java 21에서 도입된 가장 혁신적인 기능 중 하나로, Java 멀티스레드 프로그래밍의 새로운 장을 열었다. 특히 I/O가 많은 서버 애플리케이션에서 성능과 메모리 효율성을 크게 향상시킬 수 있다. 대부분의 Java 프레임워크(예: Spring, Quarkus 등)도 이미 가상 스레드를 지원하거나 지원 예정이므로, Java 21로의 업그레이드는 더 이상 선택이 아닌 필수일 것이다.