ConcurrentHashMap 은 멀티스레드 환경에서 데이터를 안전하고 효율적으로 관리할 때 자주 사용하는 클래스다.
예로, 웹 서버에서 사용자 요청 수를 집계하거나 캐시 데이터를 저장할 때, 데이터 충돌 없이 빠르게 동작한다.
ConcurrentHashMap
- 동시성 환경에서 안전한 해시맵 구현체
- Java8 부터는 CAS(Compare And Swap) 와 세밀한 락으로 동시성 최적화.
- 읽기는 락 없이, 쓰기는 최소 범위만 락 걸림
- 기본 초기 용량값은 16
사용목적
- 멀티스레드 환경에서 데이터 일관성 유지 및 성능 향상
주요메서드
- put(K key, V value): 키-값 쌍 추가 또는 갱신
- get(Object key): 키로 값 조회
- remove(Object key): 키-값 쌍 삭제
- computeIfAbsent(K key, Function<K, V> mappingFunction): 키 없으면 값 계산 후 추가
- forEach(BiConsumer<K, V> action): 모든 항목 순회
- size(): 현재 크기 반환 (정확성 보장 안 됨)
HashMap 과의 차이
- HashMap: 단일 스레드용, 동기화 없음
- Collections.synchronizedMap: 전체 락으로 동기화, 성능 저하
- ConcurrentHashMap: 세그먼트 락/CAS로 동시성 최적화, 읽기 락 없음
장점
- 높은 동시성 : 읽기 작업은 락 없이 처리, 쓰기 충돌 최소화
- 성능 : 여러 스레드가 동시에 작업 시 synchronized보다 빠름
- 안전성 : 데이터 무결성 보장
- 확장성 : 스레드 수 증가해도 성능 저하가 적음
단점
- 복잡성 : 내부 동작 이해가 필요하다. 단순 작업에는 과도한 작업을 수 있다.
- 메모리 : 세그먼트 구조로 일반 HashMap보다 사용량이 많음
- 정확성 제한 : size() , isEmpty() 는 순간값, 완전 정확성이 보장되지 않음.
- 제한 : key / value 에 Null 허용 안 함
public class ConcurrentMapBasic {
private static final ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
map.put("key" + i, i);
System.out.println(Thread.currentThread().getName() + " 추가: key" + i);
}
});
Thread t2 = new Thread(() -> {
for (int i = 100; i < 200; i++) {
map.put("key" + i, i);
System.out.println(Thread.currentThread().getName() + " 추가: key" + i);
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("최종 크기: " + map.size());
System.out.println("key10 값: " + map.get("key10"));
}
}
//출력값
Thread-0 추가: key0
Thread-0 추가: key1
Thread-0 추가: key2
Thread-0 추가: key3
...
...
...
Thread-1 추가: key197
Thread-1 추가: key198
Thread-1 추가: key199
최종 크기: 200
key10 값: 10
두 스레드가 충돌 없이 데이터를 추가한다.
- 최종크기 200 / 데이터 무결성 유지
--
일반 HashMap 으로 변경했을 경우
- 일반 HashMap 은 동기화가 없어서 경쟁 상태(race condition) 이 발생.
- 동일 키에 대해 두 스레드가 동시에 쓰면 값이 덮어씌어지거나 누락
private static final HashMap map = new HashMap();
//결과값
...
...
...
Thread-0 추가: key99
최종 크기: 199 (무결성 유지 X)
key10 값: 10
'Language > JAVA' 카테고리의 다른 글
[자바 멀티스레딩] 자바 동시성 고급: CountDownLatch 사용법 (0) | 2025.03.31 |
---|---|
[자바 멀티스레딩] 자바 동시성 고급: ReentrantLock 사용법 (0) | 2025.03.30 |
[자바 멀티스레딩] 동시성 제어: volatile 사용법 (0) | 2025.03.28 |
[자바 멀티스레딩] 동기화: synchronized 과 AtomicInteger 사용법 (0) | 2025.03.28 |
[자바 멀티스레딩] 스레드 풀: ExecutorService 사용법 (0) | 2025.03.27 |
댓글