Java ConcurrentHashMap 마스터: 연산, 예제, 모범 사례
Java ConcurrentHashMap
Java ConcurrentHashMap 클래스를 생성, 조작하는 방법과 핵심 장점을 실전 코드 예제로 알아봅니다.
ConcurrentHashMap 클래스는 Java 컬렉션 프레임워크에서 스레드 안전 맵 구현을 제공합니다. 여러 스레드가 맵의 무결성을 해치지 않고 동시에 읽고 쓸 수 있습니다.
ConcurrentMap 인터페이스를 구현하며 java.util.concurrent 패키지에 속합니다.
ConcurrentHashMap 생성하기
클래스 임포트:
import java.util.concurrent.ConcurrentHashMap;
인스턴스화. 초기 용량과 부하 계수 지정 또는 기본값 사용:
// 용량 8, 부하 계수 0.6
ConcurrentHashMap<Key, Value> numbers = new ConcurrentHashMap<>(8, 0.6f);
매개변수
capacity – 초기 버킷 수(예제에서 8)
loadFactor – 맵이 60% 찰 때 리사이즈 트리거
기본 생성자는 용량 16, 부하 계수 0.75 맵 생성:
ConcurrentHashMap<Key, Value> numbers1 = new ConcurrentHashMap<>();
기존 맵에서 ConcurrentHashMap 생성하기
다른 맵의 엔트리로 새 ConcurrentHashMap 채우기:
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap;
class Main {
public static void main(String[] args) {
HashMap<String, Integer> evenNumbers = new HashMap<>();
evenNumbers.put("Two", 2);
evenNumbers.put("Four", 4);
System.out.println("HashMap: " + evenNumbers);
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>(evenNumbers);
numbers.put("Three", 3);
System.out.println("ConcurrentHashMap: " + numbers);
}
}
출력
HashMap: {Four=4, Two=2} ConcurrentHashMap: {Four=4, Two=2, Three=3}
ConcurrentHashMap 주요 메서드
요소 삽입
put(K key, V value) – 매핑 추가 또는 교체
putAll(Map<? extends K, ? extends V> m) – 대량 삽입
putIfAbsent(K key, V value) – 키가 없을 때만 삽입
ConcurrentHashMap<String, Integer> evenNumbers = new ConcurrentHashMap<>();
evenNumbers.put("Two", 2);
evenNumbers.put("Four", 4);
evenNumbers.putIfAbsent("Six", 6);
System.out.println("Even numbers: " + evenNumbers);
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
numbers.put("One", 1);
numbers.putAll(evenNumbers);
System.out.println("Numbers: " + numbers);
출력
Even numbers: {Six=6, Four=4, Two=2} Numbers: {Six=6, One=1, Four=4, Two=2}
요소 접근
뷰 컬렉션 또는 키/값 검색 메서드 사용:
entrySet(), keySet(), values() – 엔트리, 키, 값 컬렉션 반환
get(K key) – 값 검색, 없으면 null
getOrDefault(K key, V defaultValue) – 값 또는 제공된 기본값 검색
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
numbers.put("One", 1);
numbers.put("Two", 2);
numbers.put("Three", 3);
System.out.println("Map: " + numbers);
System.out.println("Entries: " + numbers.entrySet());
System.out.println("Keys: " + numbers.keySet());
System.out.println("Values: " + numbers.values());
int val = numbers.get("Three");
System.out.println("get(\"Three\"): " + val);
int def = numbers.getOrDefault("Five", 5);
System.out.println("getOrDefault(\"Five\", 5): " + def);
출력
Map: {One=1, Two=2, Three=3} Entries: [One=1, Two=2, Three=3] Keys: [One, Two, Three] Values: [1, 2, 3] get("Three"): 3 getOrDefault("Five", 5): 5
엔트리 제거
remove(K key) – 매핑 삭제하고 값 반환
remove(K key, V value) – 현재 값이 일치할 때만 삭제, 불리언 반환
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
numbers.put("One", 1);
numbers.put("Two", 2);
numbers.put("Three", 3);
int removed = numbers.remove("Two");
System.out.println("Removed value: " + removed);
boolean deleted = numbers.remove("Three", 3);
System.out.println("Entry {Three=3} removed? " + deleted);
System.out.println("Updated map: " + numbers);
출력
Removed value: 2 Entry {Three=3} removed? true Updated map: {One=1}
대량 연산
이 메서드들은 병렬 처리를 활용해 대용량 맵을 효율적으로 처리합니다.
forEach()
엔트리 순회(선택적으로 병렬)하며 컨슈머 적용.
numbers.forEach(4, (k, v) -> System.out.println("key: " + k + " value: " + v));
// 트랜스포머 포함:
numbers.forEach(4, (k, v) -> v, (v) -> System.out.print(v + ", "));
여기서 4는 병렬 임계값 – 맵에 최소 4개 요소가 있으면 연산이 동시 실행될 수 있습니다.
search()
조건을 만족하는 엔트리 검색. 첫 매치 반환.
String key = numbers.search(4, (k, v) -> v == 3 ? k : null);
System.out.println("Searched key: " + key);
reduce()
리듀서로 값 집계. 합계, 곱, 커스텀 누적에 유용.
int sum = numbers.reduce(4, (k, v) -> v, (v1, v2) -> v1 + v2);
System.out.println("Sum of values: " + sum);
ConcurrentHashMap vs HashMap
- 스레드 안전성 –
ConcurrentHashMap은 안전한 동시 수정 허용, HashMap은 비스레드 안전
- 대량 메서드 –
ConcurrentHashMap은 병렬 처리를 위한 forEach, search, reduce 제공
왜 ConcurrentHashMap을 사용하는가?
- 최소 블로킹으로 고동시성 지원
- 내부적으로 16개 세그먼트 분할, 최대 16개 스레드가 다른 세그먼트 동시 수정 가능
putIfAbsent 같은 연산으로 의도치 않은 덮어쓰기 방지
- 내장 동기화로 외부 락 불필요