여러 스레드에서 java.util.HashMap의 값을 얻는 것이 안전합니까?


138

맵이 생성되는 경우가 있으며 일단 초기화되면 다시는 수정되지 않습니다. 그러나 여러 스레드에서 (get (key)만을 통해) 액세스됩니다. java.util.HashMap이런 식으로 사용하는 것이 안전 합니까?

(현재, 내가 행복하게을 사용하고 java.util.concurrent.ConcurrentHashMap, 성능을 개선 할 측정 필요가 없지만, 간단한 경우 단순히 궁금 HashMap충분할 것입니다. 따라서,이 질문은 하지 ? "하나는 내가 사용해야하는"도 아니다 성능 질문입니다. 문제는 "안전할까요?"입니다.


4
여기에서 많은 답변은 실행중인 스레드에서 상호 제외에 대해서는 정확하지만 메모리 업데이트에 대해서는 올바르지 않습니다. 그에 따라 투표를했지만 투표는 여전히 긍정입니다.
히스 국경

@Heath Borders, 인스턴스 a가 정적으로 초기화 할 수없는 HashMap으로 초기화 된 경우 동시 읽기 (안전하지 않은 다른 스레드는 업데이트가 없으므로 업데이트를 놓칠 수 없으므로)가 안전해야합니다.
kaqqao

정적으로 초기화되고 정적 블록 외부에서 수정되지 않은 경우 모든 정적 초기화가에 의해 동기화되므로 문제가 없을 수 있습니다 ClassLoader. 그 자체로 별도의 질문을 할 가치가 있습니다. 실제 성능 문제를 일으키는 지 확인하기 위해 여전히 명시 적으로 동기화합니다.
히스 국경

@HeathBorders- "메모리 업데이트"는 무엇을 의미합니까? JVM은 가시성, 원 자성, 이전 관계 와 같은 것을 정의 하지만 "메모리 업데이트"와 같은 용어를 사용하지 않는 공식 모델입니다 . JLS의 용어를 사용하는 것이 바람직합니다.
BeeOnRope

2
@Dave-8 년이 지난 후에도 여전히 답을 찾지 못했다고 가정하지만, 기록상 거의 모든 답에서 핵심적인 혼란 은 맵 객체대한 행동에 집중한다는 것 입니다. 이미 개체를 수정하지 않았으므로 모두 관련이 없다고 이미 설명했습니다. 그렇다면 유일하게 "gotcha"는 설명하지 않은에 대한 참조게시하는 방법Map 입니다. 안전하게하지 않으면 안전하지 않습니다. 안전하게 수행 하면됩니다 . 내 답변의 세부 사항.
BeeOnRope

답변:


55

귀하의 관용구는 참조 가 안전하게 게시 된 경우에만 안전 합니다 . 안전한 게시 는 자체 내부와 관련된 것이 아니라 구성 스레드가 다른 스레드에서 맵에 대한 참조를 표시하는 방법을 처리합니다.HashMapHashMap

기본적으로 여기서 가능한 유일한 경주 HashMap는 완전히 구성되기 전에 액세스 할 수있는 읽기 스레드와 읽기 스레드 사이의 구성입니다 . 대부분의 토론은지도 객체의 상태에 대한 문제에 관한 것이지만, 절대 수정하지 않기 때문에 이는 관련이 없습니다. 따라서 흥미로운 부분은 HashMap참조가 게시되는 방법입니다.

예를 들어, 다음과 같이지도를 게시한다고 가정하십시오.

class SomeClass {
   public static HashMap<Object, Object> MAP;

   public synchronized static setMap(HashMap<Object, Object> m) {
     MAP = m;
   }
}

... 어느 시점 setMap()에서 맵과 함께 호출되고 다른 스레드가 SomeClass.MAP맵에 액세스하는 데 사용 하고 다음과 같이 null을 확인합니다.

HashMap<Object,Object> map = SomeClass.MAP;
if (map != null) {
  .. use the map
} else {
  .. some default behavior
}

이다 안전하지 그것이 것처럼 아마 나타나더라도. 문제가없는 것이 없다 일 - 전 세트 사이의 관계 SomeObject.MAP와 다른 스레드에서 이후의 읽기, 읽기 스레드가 부분적으로 구축지도를 볼 무료 있도록. 이것은 거의 모든 작업을 수행 할 수 있으며 실제로 읽기 스레드를 무한 루프에 넣는 것과 같은 작업을 수행합니다 .

안전지도를 게시하려면이 설정해야합니다 발생-전에 사이의 관계 참조 서면으로 받는 HashMap(즉, 출판 ) 및 해당 참조 (즉, 소비)의 후속 독자. 편리하게, 이를 달성 하기 위한 기억하기 쉬운 몇 가지 방법 이 있습니다 [1] :

  1. 올바르게 잠긴 필드를 통해 참조 교환 ( JLS 17.4.5 )
  2. 정적 초기화 프로그램을 사용하여 초기화 저장소를 수행하십시오 ( JLS 12.4 )
  3. 변동성 필드 ( JLS 17.4.5 )를 통해 또는이 규칙의 결과로 AtomicX 클래스를 통해 참조를 교환하십시오.
  4. 최종 필드 ( JLS 17.5 ) 로 값을 초기화하십시오 .

시나리오에서 가장 흥미로운 것은 (2), (3) 및 (4)입니다. 특히 (3)은 위의 코드에 직접 적용됩니다 MAP.

public static volatile HashMap<Object, Object> MAP;

아닌 값 을 보는 독자는 반드시 상점과 관계가 있어야 하기MAP 때문에 맵 초기화와 연관된 모든 상점을 볼 수 있습니다.

(2) (정적 이니셜 라이저 사용) 및 (4) ( final 사용 ) 모두 MAP런타임에 동적으로 설정할 수 없음을 의미하므로 다른 메소드는 메소드의 의미를 변경합니다 . 당신이하지 않으면 필요 그렇게, 그럼 그냥 선언 MAPA와 static final HashMap<>당신은 안전 게시를 보장합니다.

실제로 규칙은 "수정되지 않은 개체"에 안전하게 액세스하기 위해 간단합니다.

본질적으로 불변 이 아닌 객체를 게시하는 경우 (선언 된 모든 필드에서 final와 같이)

  • 선언 순간에 할당 될 객체를 이미 만들 수 있습니다. a : final필드를 사용하십시오 ( static final정적 멤버 포함).
  • 참조가 이미 표시된 후에 나중에 오브젝트를 지정하려고합니다 . 휘발성 필드 b를 사용하십시오 .

그게 다야!

실제로는 매우 효율적입니다. a의 사용 static final분야는, 예를 들어, JVM은 값이 프로그램의 삶에 대한 변경 가정하고 무겁게을 최적화 할 수 있습니다. (A)의 사용 final부재 필드 있도록 대부분의 구조는 일반 필드 판독하는 방법 당량의 필드를 판독하고 억제되지 않는 상기 최적화 된 C를 .

마지막으로 사용하면 volatile영향을 미칩니다. 많은 아키텍처 (예 : x86, 특히 읽기가 읽기를 허용하지 않는 아키텍처)에는 하드웨어 장벽이 필요하지 않지만 컴파일시 일부 최적화 및 재정렬이 발생하지 않을 수 있습니다. 효과는 일반적으로 작습니다. 그 대가로 실제로 요청한 것보다 더 많은 것을 얻을 수 있습니다. 안전하게 게시 할 수있을뿐만 아니라 동일한 참조에 대해 원하는만큼 HashMap수정하지 않은 수를 더 많이 저장할 수 HashMap있으며 모든 독자에게 안전하게 게시 된지도가 표시됩니다. .

자세한 내용은 Shipilev 또는 Manson and Goetz의 FAQ를 참조하십시오 .


[1] shipilev 에서 직접 인용 .


a 복잡해 보이지만, 선언 시점이나 생성자 (멤버 필드) 또는 정적 초기화 기 (정적 필드)에서 생성시 참조를 할당 할 수 있습니다.

b 선택적으로 synchronized메소드를 사용 하여 가져 오거나 설정할 수 AtomicReference있지만 할 수있는 최소 작업에 대해 이야기하고 있습니다.

c 매우 약한 메모리 모델을 가진 일부 아키텍처 ( 알파, 나는 당신을보고 있습니다 )는 읽기 전에 어떤 유형의 읽기 장벽이 필요할 수 final있지만 오늘날에는 매우 드 rare니다.


never modify HashMapstate of the map object내가 생각하는 스레드 안전을 의미하지는 않습니다 . 공식 문서가 스레드 안전하다고 말하지 않으면 라이브러리 구현을 알고 있습니다.
Jiang YD

@JiangYD-어떤 경우에는 회색 영역이 있습니다. "수정"이라고 할 때 실제로 의미하는 것은 다른 스레드에서 읽기 또는 쓰기와 경쟁 할 수있는 일부 쓰기 를 내부적으로 수행하는 작업입니다 . 이러한 쓰기는 내부 구현 세부 정보 일 수 있으므로 "읽기 전용"으로 보이는 작업도 get()실제로 일부 쓰기를 수행 할 수 있습니다 (예 : 일부 통계 업데이트 (또는 LinkedHashMap액세스 순서가 지정된 액세스 순서 업데이트의 경우 )). 따라서 잘 작성된 수업은 다음과 같은 경우를 명확히하는 문서를 제공해야합니다.
BeeOnRope

... 분명히 "읽기 전용"작업은 스레드 안전성 측면에서 실제로 내부적으로 읽기 전용입니다. 예를 들어 C ++ 표준 라이브러리에는 표시되는 멤버 함수 const가 이러한 의미에서 실제로 읽기 전용 이라는 담요 규칙이 있습니다 (내부적으로 여전히 쓰기를 수행 할 수 있지만 스레드로부터 안전해야 함). constJava 에는 키워드 가 없으며 문서화 된 담요 보증을 알고 있지 않지만 일반적 으로 표준 라이브러리 클래스는 예상대로 작동하고 예외가 문서화됩니다 ( LinkedHashMap예 : RO ops get가 명시 적으로 안전하지 않은 것으로 언급 된 예 참조 ).
BeeOnRope 1

@JiangYD-마지막으로, 원래 질문으로 돌아가서, HashMap우리는 실제로이 클래스에 대한 스레드 안전성 동작을 문서화했습니다 . 여러 스레드가 동시에 해시 맵에 액세스하고 스레드 중 하나 이상이 맵을 구조적으로 수정하는 경우, 외부 적으로 동기화되어야합니다. (구조적 수정은 하나 이상의 매핑을 추가하거나 삭제하는 작업입니다. 인스턴스에 이미 포함되어있는 키와 관련된 값을 변경하는 것만으로는 구조적 수정이 아닙니다.)
BeeOnRope

따라서 HashMap읽기 전용으로 예상되는 메소드의 경우 구조적으로을 수정하지 않으므로 읽기 전용 HashMap입니다. 물론,이 보증은 임의의 다른 Map구현에는 적용 되지 않을 수도 있지만 문제는 HashMap구체적입니다.
BeeOnRope 1

70

Java 메모리 모델에 관한 신인 Jeremy Manson은이 주제에 대해 세 부분으로 구성된 블로그를 가지고 있습니다. 본질적으로 "불변 HashMap에 액세스해도 안전합니까?"라는 질문을하기 때문입니다. 그러나 "내 HashMap이 변경 불가능하다"라는 질문에 대한 술어에 응답해야합니다. Java는 불변성을 결정하기 위해 비교적 복잡한 규칙 세트를 가지고 있습니다.

이 주제에 대한 자세한 내용은 Jeremy의 블로그 게시물을 참조하십시오.

Java 불변성에 대한 1 부 : http://jeremymanson.blogspot.com/2008/04/immutability-in-java.html

Java 불변성에 대한 2 부 : http://jeremymanson.blogspot.com/2008/07/immutability-in-java-part-2.html

Java 불변성에 대한 3 부 : http://jeremymanson.blogspot.com/2008/07/immutability-in-java-part-3.html


3
좋은 지적이지만 정적 초기화에 의존하고 있는데 그 동안 참조가 이스케이프되지 않으므로 안전해야합니다.
Dave L.

5
나는 이것이 어떻게 높은 등급의 답변 (또는 심지어 답변)인지 알지 못합니다. 그것은 하나 의 질문에 대답 조차 하지 않으며 그것이 안전한지 아닌지를 결정하는 중요한 원칙을 언급하지 않습니다 : 안전한 출판 . "답변"은 "간단히"로 요약되며 여기에 읽을 수있는 세 개의 (복잡한) 링크가 있습니다.
BeeOnRope

그는 첫 번째 문장의 끝에서 질문에 대답합니다. 대답의 관점에서, 그는 불변성 (질문의 첫 번째 단락에서 언급 된)이 그 주제를 더 설명하는 귀중한 자료와 함께 간단하지 않다는 점을 제기하고 있습니다. 요점은 답변인지 여부를 측정하는 것이 아니라 답변이 다른 사람에게 "유용한"것인지를 측정합니다. 수락 된 답변은 OP가 찾고 있던 답변이었으며 귀하의 답변이 접수되었습니다.
Jesse

@Jesse 첫 문장 끝에서 질문에 대답하지 않고 다음 문장에서 지적한 것처럼 OP의 질문에 적용되거나 적용되지 않는 "불변의 객체에 액세스하는 것이 안전합니까?"라는 질문에 답합니다. 본질적으로 이것은 거의 링크 전용의 "직접 생각하십시오"형식 답변이며, 이는 SO에 대한 좋은 답변이 아닙니다. upvotes에 관해서는, 나는 그것이 10.5 세의 기능이며 자주 검색되는 주제라고 생각합니다. 지난 몇 년 동안 아주 적은 수의 순 투표를 받았기 때문에 사람들이오고있을 것입니다 :).
BeeOnRope

35

읽기는 동기화 관점에서는 안전하지만 메모리 관점에서는 안전하지 않습니다. 이것은 여기에 Stackoverflow를 포함하여 Java 개발자들 사이에서 널리 이해되는 것입니다. ( 증거 를 위해이 답변 의 등급을 준수하십시오 .)

다른 스레드가 실행중인 경우 현재 스레드에서 메모리 쓰기가 없으면 업데이트 된 HashMap 사본이 표시되지 않을 수 있습니다. 메모리 쓰기는 동기화 또는 휘발성 키워드를 사용하거나 일부 Java 동시성 구성을 사용하여 발생합니다.

자세한 내용 은 새로운 Java 메모리 모델에 대한 Brian Goetz의 기사 를 참조하십시오.


이중 제출 Heath에 대해 유감스럽게 생각합니다. :)
Alexander

2
실제로 기억 효과를 이해하는 다른 사람들이 있다는 것이 기쁩니다.
히스 국경

1
실제로, 스레드가 제대로 초기화되기 전에 객체를 볼 수는 없지만이 경우에는 이것이 문제라고 생각하지 않습니다.
Dave L.

1
이는 개체가 초기화되는 방식에 전적으로 달려 있습니다.
Bill Michell

1
문제는 일단 HashMap이 초기화되면 더 이상 업데이트하지 않을 것이라고 말합니다. 그런 다음에는 읽기 전용 데이터 구조로 사용하려고합니다. 그의지도에 저장된 데이터는 변하지 않는다면 그렇게하는 것이 안전 할 것이라고 생각합니다.
Binita Bharati

9

좀 더 살펴본 후에 java doc (강조 광산) 에서 이것을 발견했습니다 .

이 구현은 동기화되지 않습니다. 여러 스레드가 동시에 해시 맵에 액세스하고 하나 이상의 스레드가 맵을 구조적으로 수정하는 경우 외부 적으로 동기화해야합니다. (구조적 수정은 하나 이상의 매핑을 추가하거나 삭제하는 작업입니다. 인스턴스에 이미 포함 된 키와 관련된 값을 변경하는 것만으로는 구조적 수정이 아닙니다.)

이것은 진술의 반대가 사실이라고 가정하면 안전 할 것임을 암시하는 것처럼 보입니다.


1
다른 답변에서 알 수 있듯이 이것은 훌륭한 조언이지만 불변하고 안전하게 게시 된지도 인스턴스의 경우 더 미묘한 답변이 있습니다. 그러나 당신이하고있는 것을 아는 경우에만 그렇게해야합니다.
Alex Miller

1
우리와 같은 질문으로 우리가 무엇을하고 있는지 알 수 있기를 바랍니다.
Dave L.

이것은 실제로 정확하지 않습니다. 다른 답변 상태로, 마지막 수정과 이후의 모든 "스레드 안전"읽기 사이에 발생 해야합니다 . 일반적으로 이것은 객체 가 생성되고 수정 된 후에 안전하게 게시해야 함을 의미합니다 . 정답으로 표시된 첫 번째를 참조하십시오.
markspace

9

어떤 상황에서는 동기화되지 않은 HashMap의 get ()이 무한 루프를 일으킬 수 있습니다. 동시 put ()으로 인해 맵이 다시 해시되는 경우에 발생할 수 있습니다.

http://lightbody.net/blog/2005/07/hashmapget_can_cause_an_infini.html


1
실제로 나는 이것이 CPU를 소비하지 않고 JVM이 멈추는 것을 보았습니다 (아마도 더 나쁩니다)
Peter Lawrey

2
나는 이 코드가 더 이상 무한 루프를 얻을 수 없도록 다시 작성되었다고 생각 합니다. 그러나 다른 이유로 여전히 동기화되지 않은 HashMap에서 가져오고 넣는 것을 치면 안됩니다.
Alex Miller

@AlexMiller는 다른 이유를 제외하고 (안전한 게시를 참조한다고 가정합니다) 문서에서 명시 적으로 허용하지 않는 한 구현 변경이 액세스 제한을 완화시키는 이유가 아니라고 생각합니다. 그런 일이으로, HashMap의 자바 독 자바 8 여전히이 경고를 포함 :Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally.
shmosel

8

그래도 중요한 비틀기가 있습니다. 맵에 액세스하는 것이 안전하지만 일반적으로 모든 스레드가 HashMap과 정확히 동일한 상태 (및 값)를 볼 수있는 것은 아닙니다. 하나의 스레드 (예 : 채워진 스레드)에 의해 수행 된 HashMap에 대한 수정 사항이 해당 CPU 캐시에있을 수 있고 메모리 펜스 작업이 완료 될 때까지 다른 CPU에서 실행중인 스레드에 표시되지 않는 다중 프로세서 시스템에서 발생할 수 있습니다. 캐시 일관성 보장을 수행했습니다. Java 언어 사양은 이것에 대해 명시 적입니다. 해결책은 메모리 차단 작업을 수행하는 잠금 (동기화 (...))을 얻는 것입니다. 따라서 HashMap을 채운 후에 각 스레드가 ANY 잠금을 획득한다고 확신하면 그 시점부터 HashMap이 다시 수정 될 때까지 모든 스레드에서 HashMap에 액세스해도됩니다.


스레드에 액세스하는 스레드가 잠금을 얻을 것이라고 확신하지는 않지만 초기화 된 후에야 객체에 대한 참조를 얻지 못하므로 오래된 사본을 가질 수 있다고 생각하지 않습니다.
Dave L.

@Alex : 동일한 메모리 가시성을 보장하기 위해 HashMap에 대한 참조가 일시적 일 수 있습니다. @ 데이브 : 이다 그것의 ctor의 작업 스레드에 표시되기 전에 새 OBJS에 대한 참조를 볼 수 있습니다.
Chris Vest

@Christian 일반적인 경우에, 확실히. 나는이 코드에서 그렇지 않다고 말하고있었습니다.
Dave L.

RANDOM 잠금을 획득한다고해서 전체 스레드 CPU 캐시가 지워지는 것은 아닙니다. JVM 구현에 따라 다르며이 방법으로 수행되지 않을 가능성이 큽니다.
Pierre

나는 Pierre에 동의합니다. 잠금을 얻는 것으로 충분하다고 생각하지 않습니다. 변경 사항이 표시 되려면 동일한 잠금에서 동기화해야합니다.
damluar

5

http://www.ibm.com/developerworks/java/library/j-jtp03304/ # 초기화 안전 에 따르면 HashMap을 최종 필드로 만들 수 있으며 생성자가 완료된 후에 안전하게 게시됩니다.

... 새로운 메모리 모델에는 생성자의 최종 필드 쓰기와 다른 스레드의 해당 객체에 대한 공유 참조의 초기로드간에 발생하는 이전 관계와 유사한 것이 있습니다. ...


이 답변은 품질이 낮으며 @taylor gauthier의 답변과 동일하지만 세부 사항은 적습니다.
Snicolas

1
음 ... 엉덩이는 아니지만, 거꾸로 있습니다. 테일러는 "아니요,이 블로그 게시물을 보시면 대답이 당신을 놀라게 할 것입니다"라고 말했지만,이 답변은 실제로 내가 알지 못한 새로운 것을 추가합니다 ... 건설자. 이 답변은 훌륭하며 읽은 것을 기쁘게 생각합니다.
Ajax

응? 이것은 높은 등급의 답변을 스크롤 한 후 찾은 유일한 정답입니다. 키는 안전하게 게시 되며 키를 언급하는 유일한 대답입니다.
BeeOnRope

3

따라서 당신이 묘사 한 시나리오는 많은 데이터를 맵에 넣어야한다는 것입니다. 그런 다음 채우기를 마치면 불변으로 취급합니다. "안전한"접근 방법 (실제로 불변으로 취급됨을 의미 함)은 불변 Collections.unmodifiableMap(originalMap)을 만들 준비가되었을 때 참조를 대체하는 것입니다.

동시에 사용하는 경우 맵이 잘못 될 수있는 방법에 대한 예제와 내가 제안한 해결 방법은 다음 버그 퍼레이드 항목을 확인하십시오. bug_id = 6423457


2
이것은 불변성을 강제한다는 점에서 "안전"하지만 스레드 안전 문제를 해결하지는 않습니다. 맵이 UnmodifiableMap 랩퍼로 액세스하기에 안전하면 맵없이 안전하며 그 반대도 마찬가지입니다.
Dave L.

2

이 질문은 Brian Goetz의 "실제로 Java 동시성"책에서 다루고 있습니다 (Listing 16.8, page 350).

@ThreadSafe
public class SafeStates {
    private final Map<String, String> states;

    public SafeStates() {
        states = new HashMap<String, String>();
        states.put("alaska", "AK");
        states.put("alabama", "AL");
        ...
        states.put("wyoming", "WY");
    }

    public String getAbbreviation(String s) {
        return states.get(s);
    }
}

이후 states로 선언 final하고 초기화, 소유자의 클래스 생성자 내에서 수행됩니다 나중에이지도를 읽는 모든 스레드가 다른 스레드를 제공하지 생성자 마감이지도의 내용을 수정하려고합니다 시간으로 볼 보장됩니다.


1

단일 스레드 코드에서도 ConcurrentHashMap을 HashMap으로 바꾸는 것은 안전하지 않을 수 있습니다. ConcurrentHashMap은 널을 키 또는 값으로 금지합니다. HashMap은 금지하지 않습니다 (요청하지 마십시오).

따라서 기존 코드가 설정 중에 컬렉션에 null을 추가 할 가능성이있는 상황 (아마도 어떤 종류의 오류가 발생한 경우)에서 설명 된대로 컬렉션을 바꾸면 기능적 동작이 변경됩니다.

즉, HashMap의 동시 읽기는 안전하지 않습니다.

[편집 : "동시 읽기"란 동시 수정이 없음을 의미합니다.

다른 답변은 이것을 보장하는 방법을 설명합니다. 한 가지 방법은 맵을 변경 불가능하게 만드는 것이지만 필요하지는 않습니다. 예를 들어, JSR133 메모리 모델은 스레드 시작을 동기화 된 조치로 명시 적으로 정의합니다. 즉, 스레드 B를 시작하기 전에 스레드 A에서 작성된 변경 사항이 스레드 B에 표시됩니다.

내 의도는 Java 메모리 모델에 대한 자세한 답변과 모순되지 않습니다. 이 답변은 동시성 문제를 제외하고 ConcurrentHashMap과 HashMap간에 API 차이가 하나 이상 있으며 이는 단일 스레드 프로그램을 다른 것으로 대체 할 수 있음을 나타냅니다.]


경고 해 주셔서 감사하지만 null 키 또는 값을 사용하려는 시도는 없습니다.
Dave L.

없을 것이라고 생각했습니다. 컬렉션의 null은 Java의 미친 코너입니다.
Steve Jessop

이 답변에 동의하지 않습니다. "HashMap에서 동시 읽기는 안전합니다"자체가 올바르지 않습니다. 변경 가능 또는 변경 불가능한 맵에 대해 읽기가 발생하는지 여부는 표시되지 않습니다. 그것은 "안전 동시는 불변의 HashMap에서 읽고"읽어야 정확합니다
테일러 고티에

2
귀하가 링크 한 기사에 따르지 않음 : 요구 사항은 맵을 변경해서는 안되며 (이전 변경 사항은 모든 독자 스레드에 표시되어야 함) 변경 불가능하지 않아야합니다 (Java의 기술적 용어이며 안전을 위해 충분하지만 필요하지 않은 조건).
Steve Jessop

참고 사항 ... 클래스를 초기화하면 동일한 잠금에서 암시 적으로 동기화됩니다 (예, 정적 필드 이니셜 라이저에서 교착 상태가 발생할 수 있음) 초기화가 정적으로 발생하면 초기화가 완료되기 전에 다른 사람이 클래스를 볼 수 없습니다. 그것들은 획득 한 동일한 잠금에서 ClassLoader.loadClass 메소드에서 차단되어야합니다 ... 그리고 같은 필드의 다른 사본을 가진 다른 클래스 로더에 대해 궁금하다면, 맞습니다 ... 그러나 그것은 직교합니다. 경쟁 조건의 개념; 클래스 로더의 정적 필드는 메모리 펜스를 공유합니다.
Ajax

0

http://www.docjar.com/html/api/java/util/HashMap.java.html

다음은 HashMap의 소스입니다. 알다시피, 잠금 / 뮤텍스 코드는 전혀 없습니다.

이것은 다중 스레드 상황에서 HashMap에서 읽을 수는 있지만 쓰기가 여러 개인 경우 ConcurrentHashMap을 사용한다는 것을 의미합니다.

흥미로운 점은 .NET HashTable과 Dictionary <K, V>가 모두 동기화 코드를 내장하고 있다는 것입니다.


2
예를 들어 임시 인스턴스 변수를 내부적으로 사용하기 때문에 단순히 읽는 동시에 문제를 일으킬 수있는 클래스가 있다고 생각합니다. 따라서 잠금 / 뮤텍스 코드에 대한 빠른 스캔보다 소스를 신중하게 검사해야 할 수도 있습니다.
Dave L.

0

초기화와 모든 풋이 동기화되면 저장됩니다.

클래스 로더가 동기화를 처리하기 때문에 다음 코드가 저장됩니다.

public static final HashMap<String, String> map = new HashMap<>();
static {
  map.put("A","A");

}

휘발성 코드를 작성하면 동기화가 처리되므로 다음 코드가 저장됩니다.

class Foo {
  volatile HashMap<String, String> map;
  public void init() {
    final HashMap<String, String> tmp = new HashMap<>();
    tmp.put("A","A");
    // writing to volatile has to be after the modification of the map
    this.map = tmp;
  }
}

final 또한 휘발성이기 때문에 멤버 변수가 final 인 경우에도 작동합니다. 그리고 메소드가 생성자 인 경우.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.