> For the complete documentation index, see [llms.txt](https://leehyokyun.gitbook.io/openbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://leehyokyun.gitbook.io/openbook/2-6.-spring-application-and-web.md).

# 2-6. Spring Application & Web 동시성

Spring Application 및 Web 동시성에 대하여

### 1. Application의 동시성 수준 비교 및 검증 인프라의 한계

* 단일 WAS 인스턴스 테스트의 특성: 멀티스레드로 테스트하는 환경은 단일 WAS 인스턴스에서의 다중 스레드 동시성 테스트를 의미한다. 이 구조는 완벽한 동일성 환경은 아니지만, 분산 환경에서도 WAS가 기본적으로 스레드 단위로 처리하므로 로컬 동시성 관점에서의 Race Condition(경쟁 상태) 가정 및 `synchronized`(동기화) Lock 동작 검증까지는 유효하게 수행할 수 있다.
* 다중 WAS 분산 동시성 테스트의 본질: 진정한 동시성 테스트를 수행하기 위해서는 실제 다중 WAS 인스턴스 환경(예: Tomcat, Jeus 등 다중 가동)에 대한 분산 동시성 테스트를 진행해야만 기술적 의미를 확보할 수 있다. 로드밸런서(LB)에 의해 Round Robin이나 Hash 알고리즘 등으로 부하가 분산되는 `localhost:8080`(WAS A), `localhost:8081`(WAS B), `localhost:8082`(WAS C) 구조에서는 JVM 메모리가 완벽하게 분리되기 때문이다. 따라서 여러 WAS 인스턴스 환경에서의 자원 경합을 정확히 파악하는 분산 동시성 테스트 인프라가 반드시 고려되어야 한다.

### 2. 세마포어(Semaphore)와 뮤텍스(Mutex)의 작동 매커니즘 및 소유권 차이점

* 세마포어와 뮤텍스의 공통 목적: 두 메커니즘 모두 다중 스레드 및 다중 프로세스 환경에서 싱글톤 객체와 같은 공유 자원에 대한 접근 제어와 일관성 유지 등 동기화 처리를 완수하기 위해 도입하는 자원 제어 체계다.
* 세마포어(Semaphore)의 카운터 기반 제어: 공유 객체를 점유하는 스레드 및 프로세스의 허용 가능한 접근 카운트 개수를 제한하는 방식이다. 다수 스레드의 동시 접근은 가능하되 그 개수를 제한하는 것이 핵심이며, 내부에 카운터(Counter) 값을 보유한다. 스레드가 자원 접근을 요청할 때 카운터가 0보다 크면 접근을 허용하고 카운터를 감소(Counting Semaphore)시키며, 0이면 대기 상태로 진입한다. 작업 완료 시에는 카운터를 다시 증가시킨다. 카운터가 0 또는 1로만 제한되는 경우는 Binary Semaphore라고 부르며 뮤텍스처럼 응용할 수 있다. 세마포어는 소유권 개념이 없으므로 락을 걸지 않은 다른 스레드가 락을 해제하는 행위가 허용된다.
* 뮤텍스(Mutex)의 상호 배제 및 소유권 제어: 상호 배제(Mutual Exclusion)를 뜻하며, 공유락 등의 소유권 체계를 적용하여 오직 Lock 점유권을 획득한 단 하나의 스레드 또는 단 하나의 프로세스만 자원에 접근할 수 있도록 차단한다. 뮤텍스는 반드시 락을 획득하여 소유권을 쥔 바로 그 스레드만이 해당 락을 해제할 수 있다는 엄격한 소유권 규칙이 존재한다.

### 3. 동시성(Concurrency)과 가시성(Visibility)의 정의 및 원자성 보장 방안

* 동시성(Concurrency)의 본질: 단일 인스턴스 환경에서 멀티 프로세스 및 멀티 스레드가 스택(Stack) 변수를 제외한 나머지 모든 공유 객체(Heap, Method 영역)를 동시에 점유하고 수정할 때 Race Condition(경쟁 상태)에 빠지는 현상과 관련된 개념이다. 이 경쟁 상태에서 각 스레드가 수행하는 연산의 원자성(Atomicity)을 완벽하게 보장하는 것이 동시성 제어의 핵심이다.
* 원자성 보장 방안: 동시성 환경에서 자원 오염을 막고 원자성을 보장하기 위해 `synchronized` 블록 선언, `Lock` 프레임워크 활용, 혹은 CAS(Compare-And-Swap) 알고리즘 기반의 `AtomicInteger` 같은 원자성 객체 자원을 명확히 활용해야 한다.
* 가시성(Visibility)의 정의: 멀티스레드 환경에서 한 스레드가 변경한 공유 자원의 값이 즉각적으로 다른 스레드에게 올바르게 보이고 인식되는가에 대한 메모리 동기화 관점의 체계다.

### 4. 자바 메모리 아키텍처에 따른 가시성 문제 발생 원인과 휘발성 제어

* 하드웨어 메모리 계층과 자바 스레드의 연동: 자바 애플리케이션 실행 시 메인 메모리(Main Memory/RAM)의 공유 자원을 참조할 때, 하드웨어 아키텍처 구조상 연산 속도 향상을 위해 CPU 내부의 자체 Cache Memory(L1, L2, L3 캐시) 및 레지스터 레이어를 적극적으로 활용한다.
* 가시성 문제의 실체적 원인: 멀티스레드 환경에서 각 스레드는 메인 메모리에서 값을 직접 읽어 연산하기보다는, 성능 최적화를 위해 자신들이 점유한 CPU 코어의 Cache Memory에 값을 복사하여 작업을 수행한다. 이로 인해 스레드 A가 공유 자원의 값을 대폭 수정했음에도 불구하고, 자신만의 캐시를 바라보고 있던 스레드 B는 수정 전의 과거 데이터를 계속 참조하는 심각한 가시성 불일치 오류가 발생한다.
* 가시성 해결을 위한 volatile 메커니즘: 자바에서 공유 변수에 `volatile` 키워드를 선언하면, 해당 변수에 대한 모든 읽기(Read)와 쓰기(Write) 연산은 CPU 캐시 메모리를 전면 거치지 않고 오직 메인 메모리(Main Memory)를 대상으로만 직접 수행된다. 이를 통해 한 스레드가 변경한 최신 데이터 상태를 다른 스레드가 즉각적으로 식별할 수 있는 메모리 가시성을 완벽하게 보장한다. 다만, `volatile`은 가시성만 보장할 뿐 연산 자체의 원자성(동시성 Lock)을 보장하는 것은 아니므로 주의가 필요한다.

### 5. ThreadLocal 변수의 격리 공간 구조와 멀티스레드 상태 관리

* ThreadLocal의 기본 개념: 특정 스레드 고유의 독립적인 로컬 영역에 변수를 격리 저장하여, 해당 스레드가 구동되는 전체 실행 컨텍스트 선상에서 자유롭게 객체를 공유하고 재사용할 수 있도록 지원하는 특수 변수 체계다.
* 스레드 안전성 확보 파이프라인: 일반적인 멤버 변수나 공유 객체는 멀티스레드가 동시에 접근할 때 동시성 파괴가 일어나지만, `ThreadLocal`에 보관된 자원은 오직 그 자원을 저장한 전담 스레드 내부에서만 접근할 수 있도록 물리적 격리가 단행된다. 파라미터로 객체를 번거롭게 유도하며 넘기지 않아도 스레드 안전성(Thread-Safe)을 완벽하게 달성할 수 있어, 사용자 인증 세션이나 트랜잭션 커넥션 컨텍스트 관리 등에 매우 핵심적으로 활용된다.

### 6. WAS Thread Pool 환경에서의 ThreadLocal 재활용프로세스와 자원 방어 규칙

* WAS 스레드 풀의 스레드 재사용 매커니즘: 톰캣(Tomcat) 등의 웹 애플리케이션 서버는 성능 오버헤드를 막기 위해 요청이 끝났다고 해서 스레드를 파괴하지 않고, 스레드 풀(Thread Pool)에 다시 반환하여 다음 사용자의 새로운 HTTP 요청을 처리하도록 재사용한다.
* 메모리 누수 및 데이터 오염 유발 단계:
  1. 사용자 A의 요청이 인입되어 스레드 풀의 1번 스레드가 배정된다.
  2. 1번 스레드가 작업을 수행하며 사용자 A의 민감한 보안 인증 정보 등을 `ThreadLocal` 변수 공간에 저장한다.
  3. 사용자 A의 요청 처리가 완전히 종료되었으나, `ThreadLocal.remove()` 연산을 수행하지 않은 채 1번 스레드가 스레드 풀로 그대로 반환된다.
  4. 이후 완전히 다른 사용자 B가 새로운 HTTP 요청을 보내자, 스레드 풀은 다시 1번 스레드를 꺼내어 배정한다.
  5. 1번 스레드는 과거 사용자 A의 정보가 지워지지 않고 남아있는 `ThreadLocal` 공간을 그대로 유지하고 있으므로, 사용자 B의 컨텍스트에서 사용자 A의 데이터가 무단 유출되거나 오염되는 치명적인 메모리 누수 및 보안 사고가 발생한다.
* 자원 방어 필수 규칙:  `ThreadLocal`을 사용하는 비즈니스 로직 영역에서는 반드시 자바의 `try - finally` 제어 블록을 엄격하게 구축해야 한다. 메인 연산이 끝나는 시점인 `finally` 블록 내부에 `ThreadLocal.remove()` 메서드를 강제 실행하여, 스레드가 풀에 반환되기 직전에 격리 저장소 내부의 모든 자원을 깨끗하게 소멸시키고 초기화하는 방어 메커니즘을 예외 없이 완수해야 한다.
