SynchronizedMap 과 Concurrent HashMap 의 깊이 있 는 연구

4605 단어 Java
javadoc 에서 Map 에 대한 설명 은 다음 과 같 습 니 다.
An object that maps keys to values . A map cannot contain duplicate keys; each key can map to at most one value. This interface takes the place of the Dictionary class, which was a totally abstract class rather than an interface. The Map interface provides three collection views, which allow a map's contents to be viewed as a set of keys, collection of values, or set of key-value mappings.
 위 에서 알 수 있 듯 이 Map 은 "key - value"요 소 를 저장 하 는 데 사 용 됩 니 다. 하나의 key 를 하나의 value 에 투사 하고 유일한 value 일 수 있 습 니 다.
Map 은 여러 가지 실현 방식 을 사용 할 수 있 습 니 다. HashMap 의 실현 은 hash 표를 사용 합 니 다.트 리 맵 은 붉 은 검 은 나 무 를 사용한다.
 
1. Hashtable 과 HashMap
이 두 가지 유형 은 주로 다음 과 같은 몇 가지 차이 가 있다.
    Hashtable 과 HashMap 은 모두 Map 인 터 페 이 스 를 실 현 했 지만 Hashtable 의 실현 은 Dictionary 추상 류 를 바탕 으로 한다.
 
    HashMap 에서 null 은 키 로 사용 할 수 있 습 니 다. 이 키 는 하나 밖 에 없습니다.하나 이상 의 키 에 대응 하 는 값 은 null 입 니 다. get () 방법 이 null 값 을 되 돌려 줄 때 HashMap 에 이 키 가 없 음 을 표시 할 수도 있 고 이 키 에 대응 하 는 값 이 null 임 을 표시 할 수도 있 습 니 다.따라서 HashMap 에 서 는 get () 방법 으로 HashMap 에 어떤 키 가 있 는 지 판단 할 수 없 으 며, contains Key () 방법 으로 판단 해 야 한다.Hashtable 에 서 는 key 든 value 든 null 이 될 수 없습니다. .
 
   이 두 가지 가장 큰 차이 점 은 Hashtable 이 스 레 드 가 안전 하 다 는 것 이다. 그 방법 은 동기 화 되 어 다 중 스 레 드 환경 에서 직접 사용 할 수 있다.HashMap 은 스 레 드 가 안전 하지 않 습 니 다.다 중 스 레 드 환경 에서 동기 화 메커니즘 을 수 동 으로 실현 해 야 한다.따라서 Collections 클래스 에서 동기 화 버 전의 HashMap 을 다 중 스 레 드 환경 으로 되 돌려 주 는 방법 을 제공 합 니 다.
 
자바 코드
public static  Map synchronizedMap(Map m) {   
    return new SynchronizedMap(m);   
 }  
이 방법 은 SynchronizedMap 을 되 돌려 줍 니 다. SynchronizedMap 클래스 는 Collections 에 정 의 된 정적 내부 클래스 입 니 다. Map 인 터 페 이 스 를 실현 하고 그 중의 모든 방법 을 synchronized 로 구현 합 니 다. 키 워드 를 동기 화 제어 하 였 다.
 
2. 잠재 적 인 라인 안전 문제
Collections 는 HashMap 에 동시 다발 버 전 SynchronizedMap 을 제공 합 니 다. 이 버 전의 방법 은 모두 동기 화 되 었 지만, 이것 이 반드시 스 레 드 가 안전 한 것 은 아 닙 니 다. 어떤 때 는 예상 치 못 한 결과 가 나 올 수 있 습 니 다.
다음 코드 와 같이:
자바 코드
// shm 는 SynchronizedMap 의 인 스 턴 스 입 니 다.   
if(shm.containsKey('key')){   
        shm.remove(key);   
}  
 이 코드 는 맵 에서 하나의 요 소 를 삭제 하기 전에 이 요소 가 존재 하 는 지 판단 하 는 데 사 용 됩 니 다. containsKey 와 reomve 방법 은 모두 동기 화 되 어 있 지만 전체 코드 는 그렇지 않 습 니 다. 이러한 사용 장면 을 고려 하 십시오. 스 레 드 A 는 containsKey 방법 을 실행 하여 true 로 돌아 가 고 실행 reove 작업 을 준비 합 니 다. 이때 다른 스 레 드 B 가 실행 되 기 시 작 했 습 니 다. containsKey 방법 을 실행 하여 t 로 돌아 갑 니 다.rue, 그리고 reove 작업 을 실 행 했 습 니 다. 그리고 스 레 드 A 가 reove 작업 을 실 행 했 을 때 이 요소 가 없 었 습 니 다. 이 코드 가 우리 가 원 하 는 대로 작 동 하도록 하 는 방법 은 이 코드 를 동기 화 하 는 것 입 니 다. 그러나 이렇게 하 는 대가 가 너무 큽 니 다.
 
교체 할 때 이 문 제 는 뚜렷하게 변 경 됩 니 다. Map 집합 은 키, 값, 키 쌍 의 집합 을 되 돌려 주 는 세 가지 방식 을 제공 합 니 다.
자바 코드
Set keySet();   
  
Collection values();   
  
Set> entrySet();  
 이 세 가지 방법 을 바탕 으로 우 리 는 보통 다음 과 같은 방식 으로 Map 의 요 소 를 방문 합 니 다.
자바 코드
Iterator keys = map.keySet().iterator();   
  
while(keys.hasNext()){   
        map.get(keys.next());   
}  
 
여기 서 주의해 야 할 것 은 키 세트 와 교체 기 는 모두 맵 의 요소 인 '보기' 이지 '복사 본' 이 아 닙 니 다. .문 제 는 바로 여기에 있 습 니 다. 하나의 스 레 드 가 맵 의 요 소 를 교체 하고 있 을 때 다른 스 레 드 가 요 소 를 수정 하고 있 을 수 있 습 니 다. 이 때 요 소 를 교체 할 때 던 질 수 있 습 니 다.  ConcurrentModificationException 。 , , 。
집합 류 의 toArray() 방법 은 실현 되 지만 복사 본 을 만 드 는 방식 의 효율 은 이전 보다 낮 습 니 다. 특히 요소 가 많은 상황 에서 다른 방법 은 교체 할 때 전체 집합 을 잠 그 는 것 입 니 다. 그러면 효율 이 더욱 낮 습 니 다.
3. 더 좋 은 선택: Concurrent HashMap
java 5 에 서 는 ConcurrentMap 인터페이스 와 구현 클래스 인 Concurrent HashMap 이 추가 되 었 습 니 다. Concurrent HashMap 은 Hashtable 및 SynchronizedMap 과 다른 잠 금 체 제 를 제공 합 니 다. Hashtable 에서 사용 하 는 잠 금 체 제 는 전체 hash 표를 한 번 에 잠 그 고 같은 시간 에 하나의 스 레 드 로 만 작 동 할 수 있 으 며, Concurrent HashMap 에 서 는 한 번 에 통 을 잠 그 고 있 습 니 다. Concurrent HashMap 에 서 는 한 통 을 잠 그 고 있 습 니 다.tHashMap 은 기본적으로 hash 표를 16 개의 통 으로 나 누 었 습 니 다. 예 를 들 어 get, put, remove 등 일반적인 작업 은 현재 필요 한 통 만 잠 글 수 있 습 니 다. 이렇게 하면 원래 한 스 레 드 만 들 어 갈 수 있 었 는데, 지금 은 16 개의 스 레 드 를 동시에 실행 할 수 있 고, 동시에 성능 을 향상 시 킬 수 있 습 니 다.
 
위 에서 말 한 16 개의 스 레 드 는 스 레 드 를 쓰 는 것 을 말 하 며, 읽 기 동작 은 대부분 잠 금 이 필요 하지 않 습 니 다. size 등 작업 을 할 때 만 전체 hash 표를 잠 가 야 합 니 다.
 
교체 에 있어 서 Concurrent HashMap 은 서로 다른 교체 방식 을 사용 합 니 다. 이러한 교체 방식 에서 iterator 가 생 성 된 후에 집합 이 바 뀌 면 더 이상 Concurrent ModificationException 을 던 지 는 것 이 아니 라 변경 할 때 new 의 새로운 데 이 터 를 사용 하여 원래 의 데 이 터 를 반영 하지 않 습 니 다. ,iterator 완료 후 헤드 포인터 를 새로운 데이터 로 바 꿉 니 다. ,이렇게 하면 iterator 스 레 드 는 원래 의 데 이 터 를 사용 할 수 있 고 스 레 드 를 쓰 는 것 도 동시에 변 화 를 완성 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기