티스토리 뷰
동시성과 병렬성의 차이와 가상 스레드 시대의 JVM 동시성 제어 전략: Spring Batch Partitioning 동시성 제어 전략까지
ebson 2026. 1. 23. 20:53
Spring Batch Partitioning 환경에서의 동시성 제어 전략
동시성과 병렬성은 자바 애플리케이션을 설계하고 운영하는 과정에서 반복적으로 등장하는 개념입니다. 가상 스레드가 도입된 이후에도 이 두 개념을 구분해서 이해하는 일은 여전히 중요합니다. 가상 스레드는 JVM의 실행 모델에 변화를 가져왔지만, 동시성 제어가 다루는 문제의 범위 자체를 바꾸지는 않았기 때문입니다. 이 글에서는 공식 기술 문서를 기준으로 동시성과 병렬성의 차이를 정리하고, 가상 스레드를 사용하는 JVM 환경에서 동시성 제어가 필요한 경우들과 그에 대한 구체적인 전략을 살펴봅니다. 이어서 Spring Batch Partitioning 환경에서 동시성을 어떻게 다뤄야 하는지도 함께 정리합니다.
동시성과 병렬성의 개념적 구분
동시성은 여러 작업이 시간적으로 겹쳐 진행될 수 있도록 프로그램을 구조화하는 개념입니다. 병렬성은 여러 작업이 실제로 동시에 실행되는 실행 환경의 특성을 의미합니다. 이 차이는 JVM과 운영체제가 스레드를 스케줄링하는 방식을 이해하는 데 중요한 기준이 됩니다.
JVM 관점에서 동시성은 여러 스레드가 동일한 메모리 공간을 어떻게 공유하고 관측하는지에 대한 문제로 다뤄집니다. 이는 Java Memory Model에서 명시적으로 정의됩니다. 반면 병렬성은 CPU 코어 수, 스케줄러 정책, 워크로드 분산과 같은 실행 환경의 요소에 더 가까운 개념입니다. 하나의 CPU 코어만 존재하는 환경에서도 여러 스레드는 동시성을 가질 수 있지만, 병렬 실행은 발생하지 않습니다. 반대로 다수의 코어가 있더라도 공유 자원 접근이 직렬화된다면 병렬성의 이점은 제한됩니다.
이러한 구분은 성능과 정합성 문제를 분리해서 바라보는 데 도움을 줍니다. 성능 저하가 항상 동시성 문제에서 비롯되는 것은 아니며, 데이터 불일치는 병렬성 부족과 직접적인 관련이 없는 경우도 많습니다.
JVM에서 동시성 제어가 다루는 문제의 범위
JVM에서 동시성 제어의 핵심은 스레드 간의 메모리 가시성과 원자성 보장입니다. Java Language Specification과 Java Memory Model은 스레드가 변수 값을 언제, 어떻게 관측할 수 있는지를 규정합니다. synchronized, volatile, 그리고 java.util.concurrent 패키지의 구성 요소들은 이러한 규칙을 안전하게 활용하기 위한 수단으로 제공됩니다.
중요한 점은 동시성 제어의 필요성이 스레드의 개수나 생성 비용과 직접적으로 연결되지 않는다는 점입니다. 스레드가 적더라도 공유 상태가 존재한다면 동시성 제어는 필요합니다. 반대로 스레드 수가 많아도 각 스레드가 완전히 독립된 상태만을 다룬다면 동시성 문제는 발생하지 않습니다. 이 기준은 JVM의 실행 모델이 변화하더라도 유지됩니다.
가상 스레드가 도입한 변화의 성격
가상 스레드는 OpenJDK의 Project Loom을 통해 도입되었습니다. 공식 문서에서는 가상 스레드를 플랫폼 스레드에 비해 생성 비용과 전환 비용이 낮은 실행 단위로 설명합니다. 이는 대규모 동시 요청을 처리하는 서버 애플리케이션에서 스레드 자원으로 인한 병목을 완화하기 위한 변화입니다.
가상 스레드는 스레드 생성과 관리 측면에서의 부담을 줄여주지만, Java Memory Model이나 동기화 규칙을 변경하지 않습니다. synchronized 블록, 락, volatile 변수는 가상 스레드 환경에서도 동일한 의미로 동작합니다. 공식 문서 역시 가상 스레드가 동시성 문제를 제거한다고 설명하지 않습니다.
따라서 가상 스레드는 병렬 실행 환경에서의 제약을 완화하는 실행 모델의 변화로 이해하는 것이 적절합니다. 동시성 제어는 여전히 공유 상태의 존재 여부와 접근 방식에 의해 결정됩니다.
가상 스레드 환경에서 동시성 제어가 필요한 경우
가상 스레드를 사용하는 JVM 환경에서도 동시성 제어가 필요한 상황은 비교적 명확합니다. 여러 스레드가 동일한 객체나 컬렉션을 수정하는 경우, 외부 시스템과의 상호작용 결과를 누적 상태로 관리하는 경우, 또는 배치 처리 과정에서 중간 결과를 공유하는 경우가 이에 해당합니다.
가상 스레드는 이러한 상황을 단순화하지 않습니다. 오히려 스레드 생성 비용이 낮아지면서 동시에 실행되는 작업 수가 증가하고, 그 결과 공유 자원에 대한 접근 빈도도 높아질 수 있습니다. 이로 인해 기존에는 드러나지 않던 경쟁 조건이나 가시성 문제가 더 자주 관측될 가능성도 있습니다. 공식 문서가 권장하는 접근 방식은 공유 상태를 최소화하고, 불가피한 경우에는 동기화 경계를 명확히 설정하는 것입니다.
가상 스레드 환경에서의 동시성 제어 전략
가상 스레드를 사용하는 환경에서의 동시성 제어 전략은 기존 JVM 환경과 본질적으로 다르지 않습니다. 다만 스레드 수 증가를 전제로 설계가 이루어질 가능성이 높아진다는 점에서, 공유 자원의 범위를 더욱 신중하게 제한할 필요가 있습니다.
공식 문서에서는 가능한 한 불변 객체를 사용하고, 상태를 지역화하며, 스레드 간 공유를 최소화하는 방향을 권장합니다. 동기화가 필요한 경우에도 범위를 최소화하여 임계 구역이 과도하게 확장되지 않도록 주의해야 합니다. 이러한 전략은 병렬성 향상을 목표로 하기보다는, 예측 가능한 동작과 데이터 정합성을 유지하기 위한 설계 판단으로 이해하는 것이 적절합니다.
Spring Batch Partitioning과 동시성의 관계
Spring Batch에서 Partitioning은 하나의 Step을 여러 파티션으로 나누어 병렬로 실행하기 위한 구조입니다. 각 파티션은 독립적인 StepExecution을 가지며, 이를 통해 처리 상태를 분리할 수 있습니다. 공식 레퍼런스는 이러한 구조를 통해 병렬 처리가 가능하다고 설명합니다.
다만 Partitioning이 동시성 문제를 자동으로 해결해 주는 것은 아닙니다. ExecutionContext는 파티션 단위로 분리되지만, 데이터베이스, 파일 시스템, 외부 API, 또는 공유 빈과 같은 리소스는 여전히 여러 파티션에서 동시에 접근될 수 있습니다. 이 경우 가상 스레드 사용 여부와 관계없이 동시성 제어가 필요합니다.
특히 ItemWriter나 리스너 컴포넌트에서 공유 자원을 다루는 경우에는 주의가 필요합니다. Spring Batch 공식 문서에서도 파티션 간 공유 상태를 최소화하고, 불가피한 경우에는 스레드 안전한 구현을 사용할 것을 권장합니다.
Partitioning 환경에서의 동시성 제어 전략
Spring Batch Partitioning 환경에서의 동시성 제어 전략은 락을 적극적으로 사용하는 방향보다는 설계 단계에서 공유 상태를 제거하는 쪽에 가깝습니다. 각 파티션이 처리할 데이터 범위를 명확히 분리하고, 결과를 병합해야 한다면 이를 단일 스레드 또는 통제된 단계에서 수행하도록 구성하는 방식이 일반적으로 권장됩니다.
공유 자원 접근이 불가피한 경우에는 해당 자원의 스레드 안전성을 명확히 보장해야 합니다. 이는 JVM 수준의 동기화 메커니즘을 사용할 수도 있고, 데이터베이스 트랜잭션 격리 수준이나 외부 시스템이 제공하는 동시성 제어 기능을 활용하는 방식일 수도 있습니다. 중요한 점은 이러한 선택이 병렬성을 높이기 위한 수단이 아니라, 데이터 정합성을 유지하기 위한 설계 판단이라는 점입니다.
가상 스레드와 배치 처리 설계에 대한 정리
가상 스레드는 Spring Batch 환경에서도 유용하게 활용될 수 있습니다. 파티션 수가 많고 각 파티션의 작업이 I/O 바운드인 경우, 스레드 자원 관리 측면에서 이점이 있습니다. 그러나 이는 실행 효율의 문제이지, 배치 처리의 동시성 요구 사항을 변경하는 요소는 아닙니다.
공식 문서를 기준으로 보면, 스레드 모델이 어떻게 변화하더라도 공유 상태에 대한 책임은 애플리케이션 설계에 남아 있습니다. 가상 스레드는 이를 대신 해결해 주지 않습니다.
정리하며
동시성과 병렬성은 서로 다른 문제를 다룹니다. 가상 스레드는 병렬 실행 환경에서의 제약을 완화하는 실행 모델의 변화이지만, JVM의 동시성 모델과 메모리 가시성 규칙을 변경하지는 않습니다. Spring Batch Partitioning 역시 병렬 처리를 가능하게 하는 구조일 뿐, 동시성 제어를 자동으로 해결해 주지는 않습니다.
이 글을 정리하면서 다시 확인하게 되는 점은, 동시성 제어가 특정 기술의 유무로 결정되는 문제가 아니라는 사실입니다. 가상 스레드 환경에서도 여전히 공유 상태가 존재하는 지점과 외부 자원과의 경계에서는 명확한 설계 판단이 필요합니다. 이러한 기준을 공식 문서에 근거해 정리해 두는 것만으로도, 이후 설계와 리뷰 과정에서 도움이 되는 참고점이 될 수 있다고 생각합니다.
'STUDY' 카테고리의 다른 글
| Java Thread는 어떻게 관리되는가: 플랫폼 스레드와 Executor 프레임워크의 역할 (0) | 2026.02.03 |
|---|---|
| Spring 생성자 주입 vs 필드 주입: 순환참조가 발생하는 이유와 설계 관점의 해결 전략 (0) | 2026.02.02 |
| Holder Idiom vs Enum: 실무에서 선택하는 Java 싱글톤 구현 (0) | 2026.01.02 |
| Java 동시성 문제 해결: 스레드 관리부터 InterruptedException 처리까지 (0) | 2026.01.02 |
| Java Virtual Threads 활용 성능 개선 전략 – 기존 Thread Pool과의 성능 차이와 적용 기준 (0) | 2025.12.30 |
- Total
- Today
- Yesterday
- Hot Key 문제
- 트래픽 처리
- Java Performance
- Spring Batch
- Redis vs DB
- DB 인덱스 성능
- Cache Avalanche
- 백엔드 성능 설계
- Cache Penetration
- 백엔드 성능
- 동시성처리
- TTL 설계
- Redis 성능 개선
- Double-Checked Locking
- Initialization-on-Demand Holder Idiom
- 트랜잭션 관리
- InterruptedException
- 캐시 성능 비교
- 백엔드 아키텍처
- DB 트랜잭션
- spring batch 5
- Redis 캐시 전략
- Enum 기반 싱글톤
- 백엔드 성능 튜닝
- mybatis
- 스레드 생명주기
- 캐시 장애
- 캐시와 인덱스
- Cache Aside
- Eager Initialization
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 | 31 |

