2016-10-02 177 views
3

我有一個Singleton類,在構造函數中進行雙重檢查。Findbugs:NP_LOAD_OF_KNOWN_NULL_VALUE - Singleton類雙重檢查

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將在那裏多個請求。所以,我們將不得不在運行時爲此爲所有請求標識創建單個對象。

謝謝,

+0

源代碼中沒有「請求ID」的概念。你能否提供[最小,完整和可驗證的例子](http://stackoverflow.com/help/mcve)? –

+0

在沒有參數的情況下在此上下文中使用「synchronized」並不合法,例如'同步(這)'。 (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元

您可以使用Guava cache使用LRU策略默認size-based eviction

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方法的訪問。它對每次訪問都有影響,而我所描述的方法僅影響第一次訪問(如果它們是併發訪問,而資源尚未創建)。這取決於你的使用情況,但我認爲這種方法總的來說影響較小。 –