( 만약 싱글코어 CPU 라면 ) 가시성 문제는 발생하지 않는다.
가시성 문제는 멀티스레드 환경에서 한 스레드가 값을 변경했을 때, 다른 스레드가 그 변경 사항을 즉시 확인하지 못하는 문제를 말합니다. 따라서 한 CPU의 캐시 메모리를 읽으면 발생하지 않는다.
그러나 동시성 문제는 발생할 수 있다. ( 동시성 문제는 값을 읽고 수정하는 작업이 중단 없이(원자적) 이루어지지 않을 때 발생합니다. )
또, 멀티 코어의 경우 각 코어가 독립적인 캐시 메모리를 가지기 때문에 가시성 문제가 발생할 수 있다.
CAS(Compare-And-Swap)란 : 동시성 문제를 해결하기 위한 비차단(Non-blocking) 알고리즘입니다. 락 없이 원자성을 보장하며, Atomic 클래스에서 이를 내부적으로 활용합니다.
CAS 동작 원리:
1. 메모리에서 현재 값(currentValue)를 읽음.
2. 기대 값(expectedValue)와 현재 값을 비교.
3. 같으면 새로운 값(newValue)으로 업데이트.
4. 다르면 실패하고 다시 시도.
장점: 락을 사용하지 않아 데드락(Deadlock)과 같은 문제가 발생하지 않음. 성능이 뛰어나며, 높은 동시성을 지원.
단점: ABA 문제: 값이 A → B → A로 변경되면, 이를 감지하지 못함.
참조(reference)와 함께 "스탬프(stamp)" 값을 원자적으로 관리하여, 참조 값이 중간에 변경되었다가 원래 값으로 돌아온 상황(ABA)을 감지할 수 있습니다.
스핀락(Spinlock): 반복적으로 실패 시 CPU 자원을 소모
synchronized
가 적용되어 불필요한 락 경합이 발생.Concurrent 컬렉션 사용
Vector
대신 CopyOnWriteArrayList
사용Hashtable
대신 ConcurrentHashMap
사용Collections.synchronizedList
대신 병렬 처리에 적합한 컬렉션 사용락 범위 최소화
락 없는 알고리즘 활용
AtomicInteger
, AtomicReference
)를 활용하거나, 락 없는 자료구조를 사용합니다.항목 | Collections.synchronizedList | CopyOnWriteArrayList |
---|---|---|
동기화 방식 | synchronized 를 통해 전체 락 적용 | 쓰기 시 배열 복사, 읽기 작업은 락 없음 |
읽기 작업 성능 | 낮음: 락 획득 필요 | 높음: 락 없이 읽기 가능 |
쓰기 작업 성능 | 중간: 락 사용으로 제한적 | 낮음: 배열 복사로 메모리 사용량 증가 |
병렬 처리 성능 | 락 경합으로 인해 병렬 처리 성능이 낮음 | 읽기 작업에서는 높은 병렬 처리 성능 |
사용 환경 | 읽기/쓰기 작업이 모두 빈번한 환경 | 읽기 작업이 빈번하고 쓰기가 드문 환경 |
Collections.synchronizedList
synchronized
키워드를 사용하여 리스트 메서드를 동기화합니다.CopyOnWriteArrayList
add
, remove
, set
)이 호출될 때마다 배열의 복사본을 생성하여 데이터를 수정합니다.Collections.synchronizedList
가 적합한 경우CopyOnWriteArrayList
가 적합한 경우put()
메서드 호출 시, 특정 키가 포함된 버킷에만 영향을 미칩니다.Collections.synchronizedMap()
메서드를 통해 동기화된 맵을 생성합니다.