Hashtable, HashMap, ConcurrentHashMap 모두 Map 인터페이스를 implements한 AbstractMap을 상속받아 구현하고 있다는 공통점이 있다.
따라서 세 클래스 모두 Map의 기능적으로만 보면 큰 차이는 없다.
Hashtable
모든 데이터 변경 메소드가 synchronized
로 선언되어 있어서, 메소드 호출 전 스레드 간의 동기화 lock을 통해 멀티 스레드 환경에서 데이터의 무결성을 보장해준다.
하지만 객체마다 Lock을 하나씩 가지고 있기 때문에 동시에 여러 작업을 해야할 때 병목현상이 발생할 수 밖에 없다.
메소드에 접근하게 되면 다른 쓰레드는 Lock을 얻을 때까지 기다려야 하기 때문이다.
Hashtable
클래스는 Thread-safe 하다는 특징이 있긴 하지만, 위와 같은 특징 때문에 멀티쓰레드 환경에서 사용하기에도 살짝 느리다는 단점이 있다.
또한 Collection Framework가 나오기 이전부터 존재하는 클래스이기 때문에 최근에는 잘 사용하지 않는 클래스이다.
HashMap
Hashtable
과 같은 동기화를 위한 장치가 없기 때문에 동기화 문제가 발생할 수 있다(non-thread-safe).
synchronized
키워드가 존재하지 않기 때문에 Map
인터페이스를 구현한 클래스 중에서 성능이 제일 좋다고 할 수 있어 멀티 쓰레드 환경이 아니라면 HashMap을 사용하기에 대체적으로 적합하다.
그 외에 put()
으로 삽입하고 get()
으로 조회하는 것 등의 사용법은 일치한다.
병목현상(BottleNeck) : 전체 시스템의 성능이나 용량이 하나의 구성 요소로 인해 제한을 받는 현상.
Hashtable
클래스의 단점을 보완하면서 Multi-Thread 환경에서 사용할 수 있도록 나온 클래스이다.
HashMap
과 다르게 key, value에 null
값을 허용하지 않고, putIfAbsent()
라는 메소드를 갖고 있다.
동기화를 지원한다는 것이 Hashtable
과 같지만 성능은 ConcurrentHashMap
이 더 우수하다.
ConcuurentHashMap
에는 Hashtable
과는 다르게 synchronized
키워드가 메소드 전체에 붙어 있지 않다.
get()
메소드에는 아예 synchronized
가 존재하지 않고, put()
메소드에는 중간에 synchronized
키워드가 존재한다.
따라서 ConcurrentHashMap
은 읽기 작업에는 여러 쓰레드가 동시에 읽을 수 있지만, 쓰기 작업에는 특정 세그먼트 또는 버킷에 대한 lock을 사용한다.
ConcurrentHashMap
은 버킷 단위로 lock을 사용하기 때문에 같은 버킷만 아니라면 lock을 기다릴 필요가 없다는 특징이 있다. (버킷당 하나의 lock을 가지고 있다.)
즉, 여러 쓰레드에서 ConcurrentHashMap
객체에 동시에 데이터를 삽입, 참조하더라도 그 데이터가 다른 세그먼트에 위치하면 서로 lock을 얻기 위해 경쟁하지 않는다.
Hashtable | HashMap | ConcurrentHashMap | |
---|---|---|---|
thread-safe (synchronized) | O | X | O |
성능 순위 | 3 | 1 | 2 |
key, value에 null 허용 | X | O | X |
사용할 상황 | 잘 사용하지 않음 | 단일 스레드에서만 map을 사용하는 경우 | 멀티 스레드 환경에서 map을 사용하는 경우 |
Reference
https://j-i-y-u.tistory.com/30
https://devlog-wjdrbs96.tistory.com/269
안녕하세요! 깔끔하게 정리해주셔서 감사합니다! 잘 이해되지 않는 부분이 있는데요, ConcurrentHashMap 설명 중 "쓰기 작업에는 특정 세그먼트 또는 버킷에 대한 lock을 사용한다." 부분에 대한 부가 설명 가능할까요??