728x90
반응형
SMALL

왜 필요할까?
- HashMap은 멀티스레드 환경에서 안전하지 않다.
- 여러 스레드가 동시에 put, get 하면 데이터 꼬임(corruption), 무한 루프, 심지어 ConcurrentModificationException이 발생할 수 있다.
- Hashtable은 스레드 안전하지만 전체에 락을 건다. → 성능 저하.
👉 그래서 등장한 게 ConcurrentHashMap이다.
동시성 처리 + 성능 두 마리 토끼를 잡기 위해 내부 구조가 다르게 설계됐다.
⚙️ 내부 구조 핵심: 분할 락(Segment Lock)
ConcurrentHashMap은 내부적으로 버킷(bucket) 을 여러 개로 쪼갠 뒤, 각 버킷별로 락을 걸어 동기화한다.
이를 Segment Lock 구조라고 한다.
- 하나의 버킷에만 변경이 발생하면 다른 버킷은 락 없이 처리 가능
- 여러 스레드가 서로 다른 버킷에 동시에 접근해도 성능 저하 없음
- 자바 8부터는 Segment 개념 대신 bin 구조 + CAS + Synchronized 를 혼합 사용해서 더 빠르게 작동한다.
기본 사용 예시
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 값 넣기
map.put("apple", 1);
map.put("banana", 2);
// 값 가져오기
System.out.println(map.get("apple"));
// 동시 업데이트
map.compute("apple", (key, val) -> (val == null) ? 1 : val + 1);
System.out.println(map.get("apple"));
주요 동시성 메서드
|
메서드
|
설명
|
|
compute
|
키의 현재 값 기반으로 새 값 계산
|
|
computeIfAbsent
|
키가 없으면 계산하여 추가
|
|
computeIfPresent
|
키가 있으면 계산하여 수정
|
|
putIfAbsent
|
키가 없을 때만 put
|
|
forEach
|
병렬 안전한 반복 처리
|
🔗 동기화 블록 vs ConcurrentHashMap 비교
|
항목
|
HashMap + synchronized
|
ConcurrentHashMap
|
|
스레드 안전성
|
O
|
O
|
|
동기화 방식
|
전체 락
|
분할 락
|
|
동시 처리
|
낮음
|
높음
|
|
성능
|
경합 많으면 저하
|
경합 많아도 유지
|
- 셀 병합
- 행 분할
- 열 분할
- 너비 맞춤
- 삭제
실전에서 언제 쓰냐?
- 다중 스레드 환경에서 캐시(Map) 관리
- 요청별 상태 저장 (예: 세션별 데이터)
- 공유 설정 데이터
- 쓰기보다 읽기가 많은 경우 효율적
주의할 점!
- size() 는 정확하지 않을 수 있다 → 동시 수정 중이면 정확 보장 X
- 대규모 연산은 forEach와 reduce 제공 → Stream API처럼 사용 가능
long count = map.mappingCount(); // size()보다 동시성에 안전
마무리
ConcurrentHashMap은 멀티스레드에서 안전한 Map 구현체 중 가장 자주 쓰인다.
성능과 안정성 모두 중요할 때 필수로 알아야 한다.
728x90
반응형
LIST
'TIPS' 카테고리의 다른 글
| Hive + Spark 실무 — 대용량 조인 성능 튜닝 실전 예제 (4) | 2025.07.14 |
|---|---|
| #빅데이터 실무에서 성능 잡아먹는 핵심 원인과 실전 대응 (2) | 2025.07.07 |
| Java Memory Model (JMM)과 volatile 키워드 — 동시성 프로그래밍의 핵심 (2) | 2025.06.23 |
| CompletableFuture — 자바의 현대적 비동기 프로그래밍 (1) | 2025.06.16 |
| ThreadLocal — 스레드별로 고립된 변수 저장소 만들기 (8) | 2025.06.09 |