3

ConcurrentMap < String, SomeObject > 개체가 있습니다. SomeObject 값이 있으면 반환하거나, SomeObject를 새로 만들고 Map에 넣고 존재하지 않으면 반환하는 메서드를 작성하려고합니다.필요한 경우에만 키를 추가 할 때 ConcurrentMap을 동기화해야합니까?

이상적으로 ConcurrentMap의 putIfAbsent(key, new SomeObject(key))을 사용할 수는 있지만 매번 새로운 SomeObject (키)를 생성한다는 것은 매우 낭비적인 것 같습니다.

그래서 나는 다음과 같은 코드에 의존하지만,이 처리하는 가장 좋은 방법입니다 것을 확실하지 않다 : 나는 인 ConcurrentMap의 적 putIfAbsent (키, 새로운 SomeObject의 (키))를 사용할 수, 이상적으로

public SomeValue getSomevalue(String key){ 

    SomeValue result = concurrentMap.get(key); 

    if (result != null) 
    return result; 

    synchronized(concurrentMap){ 

    SomeValue result = concurrentMap.get(key); 

    if (result == null){ 
     result = new SomeValue(key); 
     concurrentMap.put(key, result); 
    } 

    return result; 
    } 
} 
+0

코드는 정확하지만 동기화 된 블록에 putIfAbsent를 사용할 수 있습니다. 더 최적이 될 것입니다. –

+0

@GuillaumeF. 좀 더 최적의 의미를 설명해 주시겠습니까? 그 시점에서 나는 동기화 된 블록 내에서 그것을 검사하고 null 값을 얻었 기 때문에 키가 없다는 것을 안다. – isapir

+0

나는 synchronized 블록 안에서 테스트를 제거하려고했다. 동기화되기 전에 이미 테스트를했기 때문에 두 번째 테스트가 null이 아닌 다른 결과를 반환 할 확률은 매우 낮습니다. 매우 드물게 실패 할 것이기 때문에 putIfAbsent를 객체의 새로운 인스턴스와 함께 사용하는 것이 더 최적 일 것입니다. 동기화 된 블록을 완전히 제거 할 수도 있습니다. –

답변

4

을 ,하지만 그것은 매번 새로운 SomeObject (키)를 생성한다는 것을 의미합니다. 이는 매우 낭비적인 것 같습니다.

그런 다음 computeIfAbsent를 사용

concurrentMap.computeIfAbsent(key, SomeObject::new); 

인 ConcurrentMap과 synchronized를 사용하여 synchronized 블록의 중간에있는지도에 대한 작업을 수행하는 다른 스레드를 방지하지 않습니다. ConcurrentMap은 동기화를 위해 맵 모니터를 사용할 것을 약속하지 않으며 ConcurrentHashMap 및 ConcurrentSkipListMap은 맵 오브젝트에서 동기화하지 않습니다.

ConcurrentMap 인터페이스는 값이 한 번만 계산되거나 키가 이미있는 경우 값이 계산되지 않는다고 약속하지 않습니다. ConcurrentHashMap은 이러한 약속을하지만 ConcurrentSkipListMap은 제공하지 않습니다.

+0

아주 좋습니다. 나는 이것이 정확히 내가 찾고 있었던 것 같아요 :) – isapir

+0

명확히 해 주셔서 감사합니다. 'ConcurrentHashMap'을 사용하고 있으므로 잘 작동합니다. – isapir

+0

'computeIfAbsent'가 Java 1.8에 추가되었으므로 Java 1.7에서 내가 게시 한 코드가 "갈 길"입니다. – isapir