2014-07-19 9 views
1

나는 약 double-checked locking와 약점을 읽었지만, synchronizedMap을 사용하면 안전하다고 생각하는지 묻습니다.더블 체크 잠금과의 맵 동기화

public class EntityUtils 
{ 
    private static final Map<String, Map<String, String>> searchMap = Collections.synchronizedMap(new HashMap<String, Map<String, String>>()); 

    private static Map<String, String> getSearchablePathMap(String key) 
    { 
     Map<String, String> pathMap = searchMap.get(key); 
     if(pathMap != null) return pathMap; 

     synchronized(searchMap) 
     { 
      // double check locking (safe for synchronizedMap?) 
      pathMap = searchMap.get(key); 
      if(pathMap != null) return pathMap; 

      pathMap = new HashMap<>(); 
      pathMap.put(..., ...); 
      ... 
      // heavy map population operations 
      ... 

      pathMap = Collections.unmodifiableMap(pathMap); 

      searchMap.put(key, pathMap); 
     } 

     return pathMap; 
    } 
} 

제안 또는 개선을 환영합니다 :

여기 내 코드입니다.

답변

4

이 경우 안전하지만 별다른 이점이 없습니다.

가장 자주 발생하는 코드 경로에서 값 비싼 동기화를 피하기 위해 이중 확인 잠금이 사용되지만, get()도 동기화되므로 실제로 하나가 아닌 두 개의 동기화 된 블록이 있습니다.

+0

두 번째'get()'은 내부 동기화 블록이지만 첫 번째는 바깥입니다. 외부의 threadafe * 객체를 사용하여 ** 손상된 ** Map을 반환 할 수 있으므로'synchronizedMap'은 * 필요합니다 *. 그것이 충분한 지 의심 스럽습니다. –

+0

물론 충분합니다. 요점은 첫 번째'get()'은 (synchronizedMap 때문에) 내부에'synchronized' 블록이 있기 때문에 어떤 성능 이점도주지 않는다는 것입니다. – axtavt

+0

맞아요, 안전하지만 이중 수표가 성능상의 이점을주지는 않습니다. 고맙습니다! –

2

java.util.concurrent.ConcurrentHashMap에는 도움이 될 putIfAbsent 방법이 있습니다.

키가 없으면 코드가 생성되어 새 맵에 채워지는 시나리오에 약간의 장애가 있습니다. 결석 상황에서 설정해야 할 값이 상당한 건설 비용을 가지면 "존재하지 않는"실행 경로에 putIfAbsent를 사용하는 데 오버 헤드가 있습니다. 그러나 건설 비용이 저렴하거나 많은 호출을 통해 상각 될 수 있다면 유용 할 수 있습니다 .

표준 라이브러리의 메소드를 사용하면 자바 동시성에 대한 전문성이없는 한 자신의 롤링보다 안전 할 가능성이 높습니다.

+0

절대적으로 맞지만, 이것은'putIfAbsent'에 대한 최악의 경우입니다. 그에 따라 제 질문을 편집했습니다. –