2016-10-02 3 views
3

Ich habe eine Singleton-Klasse mit Doppelprüfung im Konstruktor.Findbugs: NP_LOAD_OF_KNOWN_NULL_VALUE - Singleton-Klasse Doppelte Überprüfung

Findbugs meldet den folgenden Fehler.

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

ich mit einem statischen Objektverweis gehen, aber die Voraussetzung ist, ein einzelnes Objekt für einen einzigartigen Request-IDs zu erstellen.

Sagen wir, Request ID 1 wird für mehrere Anfragen da sein. Daher müssen wir zur Laufzeit ein einzelnes Objekt für alle Request-IDs erstellen.

Danke,

+0

Es gibt keine Idee der «Request ID» im Quellcode. Könnten Sie bitte [ein minimales, vollständiges und überprüfbares Beispiel] (http://stackoverflow.com/help/mcve) bereitstellen? –

+0

Es scheint nicht legal zu sein, in diesem Zusammenhang ohne ein Argument, z.B. 'synchronisiert (das)'. (http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.19) Können Sie sicherstellen, dass Sie uns den richtigen Code zeigen? – ajb

+0

Sorry, habe nicht den kompletten Code eingegeben. Habe jetzt aktualisiert. – user1578872

Antwort

0

Sie einen ConcurrentMap anstelle des Doppelrückschlagsperrmuster verwendet werden soll. Ihre Methode ist in Bezug auf die Sichtbarkeit von Elementen der Karte nicht korrekt (weitere Informationen zur Sichtbarkeit finden Sie unter 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 {} 
} 

bearbeiten zu 10 Elementen mit LRU-Ersetzungsstrategie begrenzen

Sie Guava cache verwenden können, die LRU-Strategie size-based eviction für Standard verwendet.

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

Ich möchte die Anzahl der Einträge auf 10 begrenzen und wenn wir versuchen, den 11. Eintrag hinzuzufügen, sollte die LRU aufgeräumt werden. Also, dachte an Wochenreferenz. Aber, wie kann ich dies mit der ConcurrentHashMap erreichen. – user1578872

+0

Was ist, wenn die Initialisierung von 'Ressource' ein langwieriger, teurer Prozess ist? Ihre Herangehensweise erlaubt es, mehrere Male von "Ressource" zu initialisieren, und nur eine einzige Instanz wird tatsächlich in die Karte eingefügt. – Antoniossss

+0

@Antoniossss Um auf nur eine Instanz zu beschränken, müssen Sie eine globale Sperre erhalten und den gesamten Zugriff auf die Methode 'getResource' serialisieren. Es wirkt sich auf alle Zugriffe aus, während sich der beschriebene Ansatz nur auf die ersten Zugriffe auswirkt (wenn sie gleichzeitig ausgeführt werden, während die Ressource noch nicht erstellt wurde). Es hängt von Ihrem Anwendungsfall ab, aber ich denke, dass dieser Ansatz im Allgemeinen eine geringere Auswirkung hat. –

Verwandte Themen