2016-10-02 5 views
3

나는 싱글 톤 클래스를 생성자에서 두 번 검사한다.Findbugs : NP_LOAD_OF_KNOWN_NULL_VALUE - 싱글 톤 클래스 더블 체크

Findbugs가 아래 오류를보고했습니다.

Load of known null value in ... NP_LOAD_OF_KNOWN_NULL_VALUE

class SomeClass { 
    private Object lock = new Object(); 
    private Map<String,Resource> resourceMap = new HashMap<>(); 

    public Resource getResource(String resourceId) { 
    if (resourceMap.get(resourceId) == null) { 
     synchronized(lock) { 
     if (resourceMap.get(resourceId) == null) 
      Resource resource = new Resource(); 
      resourceMap.put(resourceId,resource); 
     } 
    } 
    return resourceMap.get(resourceId); 
    } 
} 

내가 정적 객체 참조와 함께 갈 수 있지만 요구 사항이 고유 요청 ID에 대한 단일 개체를 만드는 것입니다

.

여러 요청에 대해 요청 ID 1이 표시됩니다. 따라서 우리는 런타임에 모든 요청 ID에 대해 단일 객체를 만들어야합니다.

감사합니다.

+0

소스 코드에는«request id»라는 개념이 없습니다. [최소한의 완전하고 검증 가능한 예제] (http://stackoverflow.com/help/mcve)를 제공해 주시겠습니까? –

+0

이 컨텍스트에서 인수없이 '동기화'된 것으로 보이지 않습니다 (예 : 'synchronized (this)'. (http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.19) 올바른 코드를 표시하는지 확인하십시오. – ajb

+0

죄송합니다. 전체 코드를 입력하지 않았습니다. 지금 업데이트했습니다. – user1578872

답변

0

이중 체크 잠금 패턴 대신 ConcurrentMap을 사용해야합니다. 귀하의 방법이지도 요소의 가시성과 관련하여 올바르지 않습니다 (가시성에 대한 자세한 내용은 question을 참조하십시오).

class SomeClass { 
    private final ConcurrentMap<String, Resource> resourceMap = new ConcurrentHashMap<>(); 

    public Resource getResource(String resourceId) { 
     return resourceMap.computeIfAbsent(resourceId, r -> new Resource()); 
    } 

    private static class Resource {} 
} 

편집 LRU 교체 전략 (10 개) 요소

당신은 기본 size-based eviction을 위해 LRU 전략을 사용 Guava cache을 사용할 수 있습니다로 제한한다.

import com.google.common.cache.*; 

class SomeClass { 
    private final LoadingCache<String, Resource> resourceMap = 
      CacheBuilder.newBuilder() 
        .maximumSize(10L) 
        .build(new CacheLoader<String, Resource>() { 
         @Override 
         public Resource load(String key) { 
          return new Resource(); 
         } 
        }); 

    public Resource getResource(String resourceId) { 
     return resourceMap.getUnchecked(resourceId); 
    } 

    private static class Resource { 
    } 
} 
+0

항목 수를 10 개로 제한하고 11 번째 항목을 추가하려고하면 LRU를 정리해야합니다. 그래서, 주 참조를 사용하는 생각. 하지만, 어떻게 ConcurrentHashMap을 사용하여이 작업을 수행 할 수 있습니다. – user1578872

+0

'resource'의 초기화가 길고 값 비싼 프로세스라면? 당신의 접근 방식은'resource '의 여러 번 초기화 될 수 있으며 실제로는 하나의 인스턴스 만이 맵에 삽입됩니다. – Antoniossss

+0

@Antoniossss 하나의 인스턴스 만 인스턴스화하도록 제한하려면 전역 잠금을 가져와 모든 액세스를'getResource' 메소드에 직렬화해야합니다. 설명 된 접근 방식은 모든 액세스에 영향을 미치지 만 첫 번째 액세스에만 영향을 미칩니다 (리소스가 아직 생성되지 않은 상태에서 동시 액세스 인 경우). 그것은 당신의 유스 케이스에 달려 있지만, 나는이 접근법이 일반적으로 더 적은 영향을 미친다고 생각합니다. –