ConcurrentHashMap이 널 키와 값을 방지하는 이유는 무엇입니까?


141

의 JavaDoc ConcurrentHashMap은 다음 과 같이 말합니다.

마찬가지로 Hashtable하지만 달리 HashMap,이 클래스는 않습니다 하지 있도록 null키 또는 값으로 사용할 수 있습니다.

내 질문 : 왜?

두 번째 질문 : 왜 Hashtablenull을 허용 하지 않습니까?

데이터를 저장하기 위해 많은 HashMap을 사용했습니다. 그러나 ConcurrentHashMapNullPointerExceptions로 변경하면 여러 번 문제가 발생했습니다.


1
나는 그것이 매우 성가신 불일치라고 생각합니다. EnumMap은 null도 허용하지 않습니다. 널 키를 허용하지 않는 기술적 제한은 분명히 없습니다. Map <K, V>의 경우 단순히 V 유형 필드는 널 키 (널 값과 값을 구분하지 않으려는 경우 아마도 다른 부울 필드)를 지원합니다.
RAY

6
더 좋은 질문은 "HashMap이 왜 널 키와 널 값을 허용합니까?"입니다. 또는 "Java가 왜 모든 유형에 널을 허용하도록 허용합니까?"또는 "Java가 왜 널을 갖도록 허용합니까?"
Jed Wesley-Smith

답변:


220

ConcurrentHashMap자신 의 저자 (Doug Lea)의 :

ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps)에서 널이 허용되지 않는 주된 이유는 비 동시 맵에서 거의 허용되지 않는 모호성을 수용 할 수 없기 때문입니다. 주요한 것은 map.get(key)return을 반환 null하면 키가 명시 적으로 매핑되고 null키가 매핑되지 않았 는지 여부를 감지 할 수 없다는 것 입니다. 비 동시 맵에서는을 통해이를 확인할 수 map.contains(key)있지만 동시에 맵에서는 통화간에 맵이 변경되었을 수 있습니다.


7
고맙지 만, 열쇠로 null을 갖는 것은 어떻습니까?
AmitW

2
Optionals를 내부적으로 값으로 사용하지
않는가

2
@benez Optional는 Java 8 기능으로 당시에 는 사용할 수 없었습니다 (Java 5). Optional실제로 s를 사용할 수 있습니다 .
Bruno

@ AmitW, 나는 ans가 동일하다고 생각합니다. 예를 들어 하나의 스레드가 키를 null로 만들고 그에 대한 값을 저장한다고 가정합니다. 그런 다음 다른 스레드가 다른 키를 null로 변경했습니다. 두 번째 스레드가 새 값을 추가하려고하면 대체됩니다. 두 번째 스레드가 값을 얻으려고 시도하면 다른 키의 값을 가져옵니다. 이러한 상황은 피해야합니다.
Dexter

44

나는, 적어도 부분적으로, 당신이 결합 할 수 있도록 생각 containsKey하고 get단일 통화로. 맵이 널을 보유 할 수있는 경우 get해당 값에 대한 키가 없거나 값이 널이어서 널을 리턴 하는지 여부를 알 수있는 방법 이 없습니다.

왜 문제가 되나요? 그렇게 할 수있는 안전한 방법이 없기 때문입니다. 다음 코드를 사용하십시오.

if (m.containsKey(k)) {
   return m.get(k);
} else {
   throw new KeyNotPresentException();
}

이후 m동시 맵, 키 k는 사이에 삭제 될 수 있습니다 containsKey그리고 get오히려 원하는 것보다 표에 결코 널을 반환하는이 조각을 일으키는 통화 KeyNotPresentException.

일반적으로 동기화를 통해 문제를 해결할 수 있지만 동시 맵으로는 작동하지 않습니다. 따라서 서명 get을 변경해야하며 이전 버전과 호환되는 방법으로 사용자가 처음에 null 값을 삽입하지 못하게하고 "키를 찾을 수 없음"의 자리 표시 자로 계속 사용하는 것이 유일한 방법이었습니다.


할 수 있습니다 map.getOrDefault(key, NULL_MARKER). 인 경우 null값은 null입니다. 이 반환 NULL_MARKER되면 값이없는 것입니다.
Oliv

@Oliv Java 8부터 만 해당 유형에 대해 적절한 널 마커가 없을 수 있습니다.
Alice Purcell

@AlicePurcell, "물론 동시지도로는 작동하지 않습니다"-왜, 동시 버전에서 비슷하게 동기화 할 수 있는지-왜 작동하지 않는지 궁금합니다. 이것을 자세히 설명해 주시겠습니까?
samshers

@samshers 동시지도 동기화 작업이 없으므로 모든 통화를 외부에서 동기화해야합니다.이 시점에서 동시지도를 사용하면 모든 성능상의 이점을 잃을뿐만 아니라 향후 유지 보수 담당자에게 함정이 생겼습니다. 당연히 동기화없이 동시지도에 안전하게 액세스 할 수있을 것으로 기대합니다.
Alice Purcell

@AlicePurcell, 좋습니다. 기술적으로는 가능하지만 유지 보수의 악몽이 될 것이므로 이후 버전의 사용자가 동시 버전에서 동기화해야한다고 기대하지 않습니다.
samshers

4

Josh Bloch 설계 HashMap; 더그 레아 디자인 ConcurrentHashMap. 나는 그것이 사소하지 않기를 바랍니다. 실제로 문제는 null이 종종 랩핑을 요구하여 실제 null이 초기화되지 않았 음을 나타낼 수 있다고 생각합니다. 클라이언트 코드에 널이 필요한 경우 널 자체 랩핑 비용 (소액이 적음)을 지불 할 수 있습니다.


2

null에서는 동기화 할 수 없습니다.

편집 : 이것은이 경우에 정확하게 이유가 아닙니다. 처음에는 동시 업데이트에 대해 잠금을 설정하거나 객체 모니터를 사용하여 무언가 수정되었는지 감지하는 데 멋진 일이 있다고 생각했지만 소스 코드 를 검사 때 잘못된 것으로 보입니다. 해시의 비트 마스크.

이 경우 Hashtable을 복사하기 위해 수행 한 것으로 의심되며 관계형 데이터베이스 세계에서는 null! = null이므로 Hashtable이 수행 한 것으로 생각되므로 null을 키로 사용하는 것은 의미가 없습니다.


응? 맵의 키와 값에는 동기화가 없습니다. 말이되지 않습니다.
Tobias Müller

다른 종류의 잠금이 수행됩니다. 그것이 "동시"가되는 이유입니다. 그러기 위해서는 매달린 객체가 필요합니다.
Paul Tomblin

2
null 값을 동기화하는 데 사용할 수있는 특수 객체가 내부에없는 이유는 무엇입니까? 예 : "private Object NULL = new Object ();". 나는 전에 이것을 본 것 같아요 ...
Marcel

다른 종류의 잠금은 무엇을 의미합니까?
Tobias Müller

실제로, 소스 코드 gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/를 살펴 보았습니다 … 개별 항목을 잠그지 않고 세그먼트 잠금을 사용하는 것으로 보입니다.
Paul Tomblin

0

ConcurrentHashMap은 스레드로부터 안전합니다. null 키와 값을 허용하지 않는 것이 스레드 안전을 보장하는 일부라고 생각합니다.


0

API 문서의 다음 스 니펫은 좋은 힌트를 제공한다고 생각합니다. "이 클래스는 스레드 안전에 의존하지만 동기화 세부 사항에는 의존하지 않는 프로그램에서 Hashtable과 완전히 상호 운용 가능합니다."

그들은 아마도 ConcurrentHashMap완벽하게 호환 가능하고 교환 가능하게 만들고 싶을 것입니다 Hashtable. 그리고 Hashtablenull 키와 값을 허용하지 않습니다.


2
그리고 Hashtable이 왜 null을 지원하지 않습니까?
Marcel

코드를 보면 Hashtable이 null 값을 허용하지 않는 명백한 이유를 알 수 없습니다. 클래스가 만들어 졌을 때부터 API 결정 일뿐입니까?! HashMap에는 내부적으로 null 경우에 대해 일부 특수 처리가 있으며 Hashtable은 그렇지 않습니다. (항상 NullPointerException이 발생합니다.)
Tobias Müller

-2

null 값을 허용하지 않는 것이 올바른 옵션이라고 생각하지 않습니다. 많은 경우에, 우리는 동시 맵에 null 값을 가진 키를 넣기를 원합니다. 그러나 ConcurrentHashMap을 사용하면 그렇게 할 수 없습니다. 앞으로 출시 될 JDK 버전이이를 지원할 수 있다고 제안합니다.


1
Javachampion 경쟁에 대해 생각해 보셨습니까?
BlackBishop

키에서 null과 같은 동작을 원할 경우 옵션을 사용하십시오.
Alice Purcell
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.