CS 정리
ConcurrentHashMap 알고쓰자
문쿼리
2025. 6. 11. 01:11
Thread-safe 하고, 성능도 고려된 HashMap
1) 키-값 삽입, 조회, 삭제
2) 조건부 연산 (putIfAbsent, computeIfAbsent, merge)
3) 병렬 루프 처리 (forEach, reduce)
* Thread-safe
: 멀티스레드 환경에서 코드나 객체가 동시에 접근돼도 문제가 발생하지 않도록 설계된 상태
? 왜 ConcurrentHashMap 은 Thread-safe 할까 ?
내부 구조 및 동시성 제어 기법
1. CAS (Compare-And-Swap) + Synchronized 최소화 (Java 8 이후)
Java 8부터는 Segment 대신 버킷 단위 락 + CAS 연산을 도입해 더 세밀한 락 제어가 가능해졌습니다.
- CAS 연산: 특정 조건이 만족될 때만 값을 변경하는 락 없는 동시성 기법입니다.
- synchronized: 필요 시 최소한의 범위에서만 사용합니다 (성능 저하 방지).
2. 읽기 연산은 락 없이 처리 (약한 일관성 제공)
대부분의 읽기 연산은 락 없이도 동작하며, 이는 락 경쟁을 줄여 성능을 높입니다.
데이터는 약간 과거 상태일 수 있지만, 일관된 상태로 읽혀집니다.
3. 트리화(Treeification)
충돌이 많은 버킷은 LinkedList → Red-Black Tree로 변환되어 검색 속도를 유지합니다.
4. 원자적 메서드 제공
동시성 환경에서도 안전하게 사용할 수 있도록 다양한 원자적 메서드를 제공합니다
- putIfAbsent() : 값이 없을 경우에만 삽입
- computeIfAbsent() : 없을 경우 계산 후 삽입
- merge() : 기존 값과 새 값을 병합
! 주요 특징 !
항목 | 설명 |
구조 | 해시 테이블 기반, 버킷 단위 락 |
락 방식 | CAS + synchronized (필요 최소한만) |
읽기 성능 | 대부분 락 없이 처리 |
쓰기 성능 | 충돌을 줄이고 빠르게 처리 |
thread-safe | 완전 지원 (단, null 키 or 값은 불가) |
사용 환경 | 병렬 캐시, 통계 집계, 요청 처리 등 |
예시 환경 및 코드
- 다수의 스레드가 동시에 맵을 읽고/쓰는 환경
- 공유 캐시, 통계 수집, 중복 작업 방지 등 병렬 처리가 필요한 상황
- HashMap은 위험하고, Hashtable은 느릴 때
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 안전한 삽입
map.putIfAbsent("coke", 1);
// 원자적 병합
map.merge("coke", 1, Integer::sum);
// 락 없이 병렬 읽기 가능
map.forEach((key, val) -> System.out.println(key + ": " + val));