///////
Search
🦒

ConcurrentHashMap은 어떤 방식으로 스레드 동시성을 보장하나요?

Hashmap은 thread-safe하지 않다
동시성을 보장받고 싶다면 synchronized 키워드를 사용하여 객체 전체에 락을 걸거나
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable { public synchronized int size() { } @SuppressWarnings("unchecked") public synchronized V get(Object key) { } public synchronized V put(K key, V value) { } }
Java
복사
java.util.Collections의 synchronizedMap 또는 java.util.concurrentConcurrentHashMap을 사용해야 한다
import java.util.concurrent.ConcurrentHashMap; public class Main { public static void main(String[] args) { ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("A", 1); int value = map.get("A"); map.remove("A"); System.out.println("Map size: " + map.size()); } }
Java
복사
ConcurrentHashMap은 map의 일부에만 lock을 건다 (읽기 할때는 X, 쓰기만)
자바 8 이전에는 내부적으로 Segment(구역)라는 개념을 만들고, 각 Segment 내부에서는 ReentrantLock을 사용하여 영역 별로 잠금을 걸 수 있도록 했다. 이렇게 하면 여러 스레드에서 동시에 데이터를 수정하더라도, 서로 다른 Segment 내의 데이터를 수정할 수 있다.
자바 8 이후부터는 각 테이블 버킷을 독립적으로 잠그는 방식을 사용한다.
빈 버킷에 노드를 삽입할 경우에는 락 대신 CAS 알고리즘 을 사용한다.
CAS: 원자성을 보장하기 위해 기대되는 값과 비교하여 일치 하는 경우에만 값을 수정
기대값(null)을 비교하여(casTabAt) 같으면(null이면) 새로운 Node를 새로운 노드를 넣고 같지않다면 다시 반복문으로 돌아간다.
해시 버킷에 이미 노드가 존재하는 경우에는 해당 버킷의 첫번째 node에 synchronized block을 사용하여 락을 걸고 하나의 스레드만 접근하도록 제어한다.
참고 자료: