문제

는 경우가 있지도 구축 할 것,그리고 그것은 초기화,그것은 다시 수정합니다.그것은 그러나,스(을 통해 얻을 수(키)만)여러 스레드에서.이 안전하게 사용 java.util.HashMap 이 방법은?

(현재,나는 행복하게 사용 java.util.concurrent.ConcurrentHashMap, 고 측정이 필요 성능을 향상시키지만,이는 단순히 궁금하다면 간단한 HashMap 는 것으로 충분합니다.따라서,이 질문 "어떤 사용해야 하나요?"도 아니다 그것은 성능을 질문입니다.오히려 질문은"는 것이 안전합니까?")

도움이 되었습니까?

해결책

당신의 관용구는 안전 는 경우에만 에 대한 참조 HashMap안전 발표.보다는 아무것도에 관한의 내부 HashMap 자체, 안전 publication 거래가 어떻게 건설을 실지도를 참조하여 표시하여 다른 스레드입니다.

기본적으로만 가능한 경 여기에 사이의 건설 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 (즉, 게시 다)및 이후의 독자들을 참조(즉,consumption).편리하게,거기에 몇 가지 기억하기 쉬운 방법 을 달성[1]:

  1. 환 참조를 통해 제대로 잠기 분야(JLS17.4.5)
  2. 사용 정체되는 이니셜라이저를 수행 초기화점(JLS12.4)
  3. 환 참조를 통한 휘발성 필드(JLS17.4.5다),또는 등의 결과로 이 규칙을 통해 AtomicX 클래스
  4. 초기화 값으로 최종 필드(JLS17.5).

사람이 가장 흥미로운 시나리오에는(2),(3)and(4).특히,(3)에 직접 적용되는 코드가 상기:변환하면 선언 MAP 하기:

public static volatile HashMap<Object, Object> MAP;

그 모든 것은 정결:독자는 누구보 non-null 값을 반드시 일기 전에 와의 관계를 저장하기 MAP 따라서 모든 저장과 관련된 지도 초기화.

다른 방법의 의미를 변경하는 방법,이를 모두(2)(를 사용하여 정적 initalizer)(4)(사용 최종)는 것을 의미를 설정할 수 없습니다 MAP 에 동적으로 런타임입니다.지 않는 경우 는 그냥 선언 MAPstatic final HashMap<> 고 당신이 보장되는 안전하 게시합니다.

에서 연습,규칙은 단순한 안전한 액세스하지 않는다"수정"개체:

게시하는 경우 객체지 본질적으로 변경할 수 없 (으로 모든 분야에서 선언 final 고):

  • 당신은 이미 만들 수 있는 객체에 할당되는 순간의 선언a:그냥 사용 final 분야(등 static final 에 대한 정적 멤버).
  • 에 할당 개체 후 나중에 참조은 이미 표시:사용 volatile 분야b.

니다.

실제로,그것은 매우 효율적입니다.의 사용 static final 분야,예를 들어,할 수 있습 JVM 을 가정한 값은 변경되지 않은 생활을 위한 프로그램의하고 최적화합니다습니다.의 사용 final 회원장 허용 아키텍처를 읽어드 방식에 해당 정상 읽지 않을 억제한 최적화c.

마지막으로,사용 volatile 는 어떤 영향을 미칠:하드웨어 장벽에 필요한 여러 아키텍쳐에(같은 x86,특히 그 허용하지 않는 읽기를 통과를 읽고),그러나 몇 가지 최적화 및 순서 발생하지 않을 수 있습에서 컴파일 시간-하지만이 효과가 일반적으로 작습니다.교환,당신은 실제로 더 이상 요청에 대한 당사-할 수 있을 뿐만 아니라 안전하게 하나를 게시 HashMap, 저장할 수 있습으로 많은지 않을 수정 HashMaps 고 싶은 대로 동일한 참조 및 안심하실 수 있는 모든 독자들을 볼 것이 안전하게 출판 지도입니다.

더 많은 피투성이 세부 사항을 참조하십시오 Shipilev이 FAQ 여 Manson 및 Goetz.


[1]직접 인용 shipilev.


a 는 복잡한 소리 하지만,무엇을 의미를 지정할 수 있습니다 참고 건설 현장에서 시간에 하나 선언 포인트 또는에서 생성자(회원의 필드)또는 정적 이니셜라이저(정적 필드).

b 선택적으로 사용할 수 있습니다 synchronized 방법 get/set,또는 AtomicReference 거나 무언가를하지만,우리가 얘기하는 최소의 일을 할 수 있습니다.

c 어떤 아키텍처는 매우 약한 메모리 모형(난 보고 당신, Alpha)필요할 수 있는 몇 가지 유형의 읽기 방벽기 final 을 읽지만 이들은 아주 드물 오늘입니다.

다른 팁

제레미 맨슨 하나님이 그것에 관해서 자바 메모리 모델는 세 가지 부분을 블로그에서 이 항목-기 때문에 본질을 묻는 질문에"안전한 액세스를 변경할 수 없 HashMap"-그 대답은 예입니다.하지만에 응답해야 합 조건자는 그 질문에는"내 HashMap 변경할 수 없".대답은 당신을 놀라게 할 수도 있습니다 Java 는 상대적으로 복잡한 설정의 규정을 결정하는 불변성.

에 대한 자세한 내용은 항목을 읽을 제레미의 블로그 게시물:

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

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

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

읽은 안전에서 동기화 관점에서 그러나지 않는 메모리 관점에서.이것은 무언가를 널리 사이에 오해 자바 개발자를 포함 여기에서 유래.(을 관찰 평가 이 답변 에 대한 증거입니다.)

이 있는 경우 다른 스레드를 실행하는,그들은 볼 수 없습니다 업데이트된 사본 HashMap 없는 경우에는 메모리 쓰기 현재의 실을 뀁니다.메모리 쓰기을 통해 발생의 사용이 동기화되는 휘발성을 키워드,또는 이를 통해 사용의 일부 java concurrency 구문으로 표현할 수 있습니다.

Brian Goetz 의 문서에 새로운 자바 메모리 모델 자세한 내용은.

후에 조금 더보고,이에 java doc (강조관):

이 구현되지 동기화됩니다. 는 경우 여러 스레드 액세스 해시지도는 동시에,고서 적어도 하나의 스레드를 수정 지도 구조상으로해야합니다, 동기화 됩니다. (구조 수정은 어떤 작업 추가하거나 삭제 하나 이상의 매핑은;바꾸기만 연결된 값 으로는 키를 이미 인스턴스 포함되지 않은 구조 수정할 수 있습니다.)

이 것을 의미하는 것으로 보인다 안전할 것이라고 가정하고 대화의 문은 거기에 사실입니다.

하나는 어떤 상황에서,get()에서는 동기화되지 않은 HashMap 을 일으킬 수 있는 무한 루프입니다.이 경우 발생할 수 있습니다 동시에 넣어()인 개작합니다.

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

중요한 강선전도 하지만입니다.그것의 안전을 지도에 액세스하지만,일반적으로 그리고 저장된 모든 쓰레드 볼 것이 정확히 동일한 상태로(따라서 값)의 HashMap.이 일이 일어날로 다중 프로세서 시스템에서 수정을 HashMap 에 의해 수행 하나의 스레드(예를 들어,하나 채워진것)에서 앉을 수 있는 CPU 의 캐시고 볼 수 없으로 스레드에서 실행되는 다른 Cpu,까지 메모리를 담은 작업을 수행을 보장 캐시에 일관성이다.Java 언어 사양은 명시적이 하나:이 솔루션은 잠금을 얻기 위해(동기화(...))방출하는 메모리를 담은 작업입니다.그래서,당신은 확실을 채우는 HashMap 각 스레드가 획득한 모든 잠금,그것은 확인서는 지점에 액세스하 HashMap 에서 어떤 thread 까지 HashMap 는 다시 수정합니다.

에 따라 http://www.ibm.com/developerworks/java/library/j-jtp03304/ #초기화 안전을 만들 수 있습니다 당신의 HashMap 최종 필드 후 생성자를 완료 될 것이 안전하게 공표된다.

...새로운 메모리 모형,거기에 무슨 일이 일어나고 있는지 평가하는 일어나기 전 간의 관계를 쓰기의 최종 분야에서 생성자 그리고 초기의 부하를 공유 참조하는 개체는 또 다른 스레드가 있습니다....

그래서 시나리오를 설명이 필요할 것입을 넣어의 무리로 데이터를,지도한 다음에는 그것을 채우를 치료로 그것을 변경할 수 없습니다.는 하나의 방법은"안전한"(의미 있을 적용하는 것 그것이 정말로 취급 변경할 수 없)을 바꾸기에 참조로 Collections.unmodifiableMap(originalMap) 할 준비가 되면 그것을 변경할 수 없습니다.

에 대한 예 얼마나 심하게도 실패 할 수 있습니다 동시에 사용하는 경우,그리고 제안된 해결 방법,내가 언급 확인하십시오 퍼레이드 항목: bug_id=6423457

되는 경고에도 하나의 스레드 코드를 교체하 concurrenthashmap 의과 HashMap 안전하지 않을 수도 있습니다.Concurrenthashmap 의 금지 null 으로 또는 키 값입니다.HashMap 금지하지 않들(묻지 않음).

그래서 가능성이 상황는 기존의 코드를 추가할 수 있습 null 컬렉션에 설치하는 동안(아마에서 실패하는 경우 몇 가지 종류),교체 컬렉션에 설명된 대로 변경됩니다능합니다.

는 말했다,제공된 당신이 아무것도 동시에서 읽습니다 HashMap 은 안전합니다.

[편집:"에 의해 동시 읽기",나이 있다는 것을 의미하지 않는 또한 동시에 수정할 수 있습니다.

다른 답을 설명하는 방법이다.방법 중 하나는 지도 변경할 수 없지만,그것은 필요하지 않습니다.예를 들어,JSR133 메모리 모델을 명시적으로 정의합 시작하는 쓰레드가 될 동기화 작업을 의미는 변경에서 스레드를 시작하기 전에 실 B 에서 볼 수 있는 실 B.

내 의도하지 않을 부정하는 사람들이 더 자세한 답변에 대해 자바 메모리 모델이다.이 대답은 의도는 점도 고객께서 동시성 문제가 적어도 하나의 API 를 사이에 차이 concurrenthashmap 의고 HashMap 수 있는 침몰시키도 하나의 스레드 프로그램으로 대체 한다.]

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

여기에는 원본 HashMap.당신이 말할 수 있습니다,거기에 절대적으로 잠그기/mutex 코드가 있다.

이 의미는 하는 동안 그것의 좋아하는에서 읽 HashMap 다중 스레드 상황에,나는 확실히 사용 concurrenthashmap 의 경우가 있었는 여러 씁니다.

무슨 흥미로운 것은 모두.NET 해시 테이블과 사전<K,V> 내장하고 있는 동기화 코드입니다.

면 초기화 모든 넣어가 동기화되 당신은 저장합니다.

다음 코드를 저장하기 때문에 클래스 로더의 동기화:

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;
  }
}

이것 또한 경우에는 변수 회원은 최종적이기 때문에 최종은 또한 휘발성이다.경고 메소드가 생성자입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top