🎯 HashTable 의 한계와 ConcurrentHashMap
ConcurrentHashMap 은 HashTable 대안으로 나온 Collection 타입입니다. HashTable 은 멀티 스레드 환경에서 항상 안전하지 않습니다. 예를 들어 다음과 같은 상황이 있다 생각해 봅시다.
Hashtable<String, Integer> table = new Hashtable<>();
if (!table.containsKey("key")) { // 1. 키가 있는지 확인
table.put("key", 1); // 2. 키가 없으면 삽입
}
위 코드를 멀티 스레드 환경에서 실행할때,
(1) 스레드 A 가 containsKey() 를 실행하고, 동시에 스레드 B 도 동일한 검사를 수행합니다.
(2) 두 스레드가 거의 동시에 put() 을 호출하게 되어, 중복된 키 삽입이 발생할 수 있습니다.
이와 같은 문제를 해결하기 위해 멀티 스레드 환경에서는 다음과 같이 HashTable 을 관리 했습니다.
방법1. 메서드나 코드 블럭에 명시적으로 동기화를 추가한다.
synchronized (table) {
if (!table.containsKey("key")) {
table.put("key", 1);
}
}
방법2. Collections.synchorizedMap 을 사용한다.
Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());
synchronized (syncMap) { // 명시적 동기화 필요
if (!syncMap.containsKey("key")) {
syncMap.put("key", 1);
}
}
이와 같은 방법을 사용해 멀티 스레드 환경에서 HashTable 을 사용하곤 했습니다. 하지만 개발자들은 귀찮은걸 가장 싫어 합니다..
그래서 나온 Collection 타입이 바로 ConcurrentHashMap 입니다.
ConcurrentHashMap 은 내부적으로 세그먼트 락(segment lock) 을 사용하여 동시성을 최적화 하고 성능을 유지하며 스레드 안전성을 보장합니다.
synchronized 키워드는 쓰레드간 동기화 Lock 때문에 느리다. 때문에 ConcurrentHashMap 은 버킷(index) 에만 락을 걸기 때문에 같은 멀티 쓰레드 환경에서 사용하더라도 HashTabel 대비 속도가 빠릅니다.
🎯 ConcurrentHashMap 사용방법
✅ 사용방법
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
// ConcurrentHashMap 생성
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 데이터 삽입
map.put("apple", 10);
map.put("banana", 20);
// 여러 스레드가 동시에 접근 (람다 표현식 사용)
Runnable task1 = () -> {
map.put("orange", 30);
System.out.println(Thread.currentThread().getName() + " 추가: " + map);
};
Runnable task2 = () -> {
map.put("grape", 40);
System.out.println(Thread.currentThread().getName() + " 추가: " + map);
};
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
// 스레드 시작
thread1.start();
thread2.start();
// 메인 스레드에서 데이터 접근
map.putIfAbsent("apple", 15); // 키가 없으면 추가
map.computeIfPresent("banana", (key, val) -> val + 5); // 기존 값 업데이트
System.out.println("최종 결과: " + map);
}
}
✅ 실행 결과
Thread-0 추가: {apple=10, banana=20, orange=30}
Thread-1 추가: {apple=10, banana=20, orange=30, grape=40}
최종 결과: {apple=10, banana=25, orange=30, grape=40}
정리해보면,
- HashMap 은 멀티 스레드 환경에서 안전하지 않지만, ConcurrentHashMap 은 내부 락을 이용해 스레드 안전성을 보장합니다.
- 동시 접근이 필요할 때 효율적이며, 키/값 조건에 따른 연산을 지원하여 유연한 데이터 처리를 제공합니다.
- 대규모 웹 서버, 캐싱 시스템, 로그 수집등 동시 처리 시스템에서 주로 사용되곤합니다.
'JAVA' 카테고리의 다른 글
[Java] LinkedList 사용법 with Java (0) | 2024.11.27 |
---|---|
[Java] 왜 equals 와 hashCode 를 함께 오버라이딩해야 할까 ? (0) | 2024.11.25 |
[Java] record 에 대해 알아보자 (2) | 2024.10.14 |
[JAVA] JAVA 와 멀티 쓰레드 (0) | 2024.07.15 |