자바에서 데이터를 key-value 형식으로 저장할 때 가장 널리 쓰이는 컬렉션으로 HashMap과 ConcurrentHashMap이 있습니다. 두 클래스 모두 Map 인터페이스를 구현하지만, 내부 동작 방식과 동시성 처리 면에서 큰 차이가 있습니다. 이 글에서는 HashMap과 ConcurrentHashMap의 구조와 특징을 비교하고, 각 컬렉션을 상황에 맞게 선택할 수 있도록 설명하겠습니다.
기본 개념: HashMap과 ConcurrentHashMap
- HashMap: 자바에서 비동기적인 key-value 구조로 데이터를 저장하는 기본 컬렉션입니다. 단일 쓰레드 환경에서 빠르고 효율적으로 동작하지만, 멀티 쓰레드 환경에서는 안전하지 않습니다. 두 개 이상의 쓰레드가 동시에 접근하여 수정할 경우 데이터 손상 위험이 있습니다.
- ConcurrentHashMap: HashMap과 달리 동시성 처리가 필요한 환경에서 사용되도록 설계된 컬렉션입니다. 여러 쓰레드가 동시에 접근해도 안전하게 사용할 수 있으며, 필요한 부분만 동기화하여 성능을 유지합니다. 멀티 쓰레드 환경에서도 안전하게 사용할 수 있는 컬렉션입니다.
내부 동작 방식의 차이
HashMap의 구조
HashMap은 내부적으로 해시 테이블 구조를 사용하며, 배열과 연결 리스트로 구성됩니다. HashMap의 put() 메서드는 키의 해시 값을 기반으로 데이터를 저장할 위치를 결정하고, get() 메서드는 해시 값을 이용해 데이터를 빠르게 검색할 수 있습니다. 자바 8부터는 버킷이 일정 크기 이상 커지면 연결 리스트 대신 트리를 사용하여 성능을 개선했습니다.
하지만 HashMap은 동기화 처리가 되어 있지 않아서 멀티 쓰레드 환경에서는 데이터를 보호하지 못해 데이터 불일치 문제가 발생할 수 있습니다.
ConcurrentHashMap의 구조
ConcurrentHashMap은 자바의 동시성 컬렉션으로, 내부적으로 세그먼트 락(Segment Lock)이라는 방식으로 동기화를 최적화합니다. 자바 8 이전에는 데이터를 세그먼트로 분할하여 각각의 세그먼트에 락을 거는 방식으로 동기화가 이루어졌습니다. 그러나 자바 8 이후부터는 CAS(Compare-And-Swap)과 배열 기반 락 분할을 사용하여 보다 세밀하게 동기화됩니다. 이를 통해 전체 컬렉션에 락을 거는 대신 부분적인 락을 통해 쓰레드 안전성을 유지하면서도 높은 성능을 유지할 수 있습니다.
주요 차이점 비교
특징 HashMap VS ConcurrentHashMap
동기화 | 지원하지 않음 | 세밀한 수준에서 동기화 |
성능 | 단일 쓰레드 환경에서 우수 | 멀티 쓰레드 환경에서도 성능 저하 최소화 |
Null 허용 여부 | null 키와 값 허용 | null 키와 값 허용하지 않음 |
사용 사례 | 단일 쓰레드 환경 또는 동기화 불필요한 경우 | 멀티 쓰레드 환경에서 안전한 맵이 필요할 때 |
사용 예시
HashMap 예시
단일 쓰레드 환경이나 멀티 쓰레드 환경에서 동시성 문제가 없는 경우 HashMap을 사용할 수 있습니다. 예를 들어, 읽기 전용 캐시 데이터를 미리 로드하여 사용하는 경우 HashMap이 적합합니다.
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("apple", 1);
hashMap.put("banana", 2);
System.out.println("HashMap: " + hashMap.get("apple"));
ConcurrentHashMap 예시
다중 쓰레드가 동시에 데이터를 추가하거나 수정해야 하는 경우, ConcurrentHashMap을 사용하여 데이터 안정성을 보장할 수 있습니다. 예를 들어, 웹 서버에서 다수의 사용자가 동시에 데이터 구조에 접근하는 경우 ConcurrentHashMap이 적합합니다.
Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("apple", 1);
concurrentMap.put("banana", 2);
// 여러 쓰레드가 동시에 접근해도 안전하게 동작
System.out.println("ConcurrentHashMap: " + concurrentMap.get("apple"));
용도 및 상황에 따른 선택 기준
HashMap을 선택해야 하는 경우
- 단일 쓰레드 환경에서 빠른 데이터 조회와 저장이 필요한 경우
- 초기 데이터를 미리 로드한 후 읽기 전용으로 사용해야 할 때
- 데이터의 일관성이 크게 중요하지 않은 상황에서
ConcurrentHashMap을 선택해야 하는 경우
- 멀티 쓰레드 환경에서 데이터를 자주 수정하거나 업데이트해야 하는 경우
- 실시간으로 데이터가 자주 변경되며 여러 사용자가 동시에 접근할 때
- 웹 애플리케이션에서 다수의 사용자 요청을 동시에 처리할 때
마무리
자바의 HashMap과 ConcurrentHashMap은 모두 key-value 형식으로 데이터를 저장할 수 있습니다. 그러나 동시성 처리 여부에 따라 각각 다른 용도에 적합합니다. 단일 쓰레드 환경에서는 HashMap이 빠르고 효율적이며, 멀티 쓰레드 환경에서는 ConcurrentHashMap이 안전하고 성능 저하를 최소화할 수 있습니다.
'JAVA' 카테고리의 다른 글
Java의 Map 컬렉션 정리: HashMap, TreeMap, LinkedHashMap 비교 (0) | 2024.11.14 |
---|---|
Java record: 불변 객체의 간결한 정의와 활용 (0) | 2024.10.23 |
Java 접근 제어자 종류와 이해 (0) | 2024.10.22 |