Java

Hashtable의 동기화(synchronization)

제주니어 2024. 12. 10. 08:41

 

Hashtable의 동기화(synchronization)는 주로 메서드 수준에서의 동기화를 통해 이루어진다.

이는 Hashtable의 메서드들이 synchronized 키워드로 선언되어 있기 때문이다.

이 동작 방식에 대해 좀 더 구체적으로 살펴보면 다음과 같다

 

메서드 수준 동기화

Hashtable의 대부분의 메서드가 synchronized 키워드를 사용하여 구현되어 있다.

이는 동시에 여러 스레드가 동일한 메서드에 접근하는 것을 차단함으로써 데이터의 일관성을 보장한다.

예를 들어, 데이터를 삽입하거나 검색할 때 사용하는 put과 get 메서드의 구현은 아래와 같다.

 

put 메서드의 구현

public synchronized V put(K key, V value) {
    // Null 값 처리
    if (key == null || value == null) {
        throw new NullPointerException();
    }

    // 해시 값을 계산하고 배열에 저장
    int hash = key.hashCode();
    // 데이터를 저장하는 로직
    ...
    return oldValue; // 기존 값 반환 (있을 경우)
}

 

get 메서드의 구현

public synchronized V get(Object key) {
    // 해시 값을 계산하여 데이터 검색
    int hash = key.hashCode();
    // 데이터를 검색하는 로직
    ...
    return value; // 검색된 값 반환
}

 

위 코드처럼 synchronized 키워드가 메서드 전체에 적용되어 있어, 한 번에 하나의 스레드만 해당 메서드에 접근할 수 있다. 이로 인해 다중 스레드 환경에서도 데이터 손상(data corruption)이나 레이스 컨디션(race condition)을 방지할 수 있다.

 

동기화의 이점과 한계

이점

  • 여러 스레드가 동시에 Hashtable을 수정하려고 할 때도 안전하게 작동한다.
  • 데이터의 일관성과 무결성을 보장한다.

한계

  • 성능 병목
    • 스레드 A가 데이터를 삽입(put)하는 동안, 스레드 B는 데이터를 검색(get)하는 작업도 대기해야 한다.
  •  전체 락/불필요한 락
    • 메서드 수준 동기화는 전체 객체에 대한 락을 생성한다. 이는 병렬성(parallelism)을 제한하여, 스레드가 많은 환경에서 ConcurrentHashMap 같은 대안을 고려해야 하는 이유가 된다.
    • 단일 스레드 환경에서는 동기화가 불필요하지만, Hashtable은 여전히 동기화를 강제하므로 HashMap보다 성능이 저하된다.
    • 모든 읽기/쓰기 작업에서 객체 수준의 락이 걸리므로, 다중 스레드 환경에서 성능 병목(bottleneck)이 발생할 수 있다.

 

동기화의 대안

ConcurrentHashMap

ConcurrentHashMap은 동기화 병목 문제를 해결하기 위해 도입되었다. 이 자료구조는 다음과 같은 특징을 가진다:

  • 버킷(bucket) 단위 동기화: 특정 키에만 락을 걸기 때문에 병렬 처리가 가능.
  • 읽기 작업 동기화 없음: 대부분의 읽기 작업은 락 없이 수행.

 

Collections.synchronizedMap

Hashtable 대신 HashMap에 동기화를 추가하고 싶다면, Collections.synchronizedMap을 사용할 수 있다:

Map<String, String> map = Collections.synchronizedMap(new HashMap<>());

 

이 방식은 동기화를 필요로 하는 경우 Hashtable보다 유연한 선택이 될 수 있다.

 

동기화 방식 선택 가이드

  • 단일 스레드 환경: HashMap을 사용.
  • 멀티 스레드 환경:
    • 동기화가 필요한 경우 ConcurrentHashMap을 우선적으로 사용.
    • 간단한 동기화가 필요할 때는 Collections.synchronizedMap을 고려.
  • 기존 코드 유지보수: Hashtable은 레거시 코드에서 주로 사용되므로, 새 프로젝트에서는 권장되지 않음.

 

결론

Hashtable의 동기화는 객체 수준 락을 통해 간단하고 안정적으로 스레드 안전성을 보장한다. 하지만 성능 병목과 같은 단점이 있어 현대적인 대안인 ConcurrentHashMap이 더 선호된다. 동기화는 데이터 일관성을 보장하는 중요한 기능이지만, 성능과 병렬성을 고려하여 적절한 자료구조를 선택하는 것이 핵심이다.