2015-11-12 8 views
7

Wenn faul Initialisierung einer statischen Singleton in Java tun Sie dies tun können:Können wir ein Java-Mitglied schmerzlos lazy laden, ähnlich wie wir es mit statischen Singletons können?

public class Bob { 

    private static class SingletonWrapper { 
     private static final Bob instance = new Bob(); 
    } 

    public static Bob getInstance() { 
     return SingletonWrapper.instance; 
    } 

} 

Da die innere Klasse SingletonWrapper nur dann, wenn zuerst die Bob() erst getInstance() aufgerufen wird erstellt zugegriffen geladen wird.

Meine Frage ist, ob es ähnliche Tricks gibt, die verwendet werden können, um eine faule Instantiierung einer Mitgliedsvariablen in einem nicht statischen Kontext zu machen.

public class Bob { 

    // Clearly this doesn't work as not lazy 
    private final InnerWrapper wrapper = new InnerWrapper(); 

    private class InnerWrapper { 
     private final Jane jane = new Jane(); 
    } 

    public Jane getJane() { 
     return wrapper.jane; 
    } 

} 

Gibt es eine Möglichkeit wir eine Instanz von Jane innerhalb Bob haben kann und haben fädeln sicher die Instanz nur auf Verlangen ohne doppelte Kontrolle Rast- oder AtomicReference zu verwenden. Idealerweise sollte die get-Methode so einfach wie die in diesen Beispielen bleiben, aber wenn dies nicht möglich ist, wäre die einfachste und schnellste mögliche (effizienteste) Ausführung der get-Methode ideal.

+0

@assylias Wie der Kommentar sagt, dass nicht faul Initialisierung tun würde. Sobald Sie einen 'Bob' erstellen, erstellen Sie auch immer und sofort einen' Jane'. –

+0

Mein schlechtes Ich habe zu schnell gelesen - Gründe, warum Sie keine AtomicReference wollen? Es wäre möglicherweise besser als die CHM-Option. – assylias

+0

@assylias Kein spezifischer Grund. Im Grunde möchte ich nur wissen, was meine Optionen sind - wenn man bedenkt, wie einfach und effektiv der statische Wrapper-Trick für die faule Initialisierung von Singletons ist, ist es eine Schande, dass wir nicht etwas Ähnliches für die faule Initialisierung von Mitgliedern finden können, –

Antwort

8

Nein, es gibt keine Synchronisierungsregeln für das Instanziieren von Typen, wie sie für das Initialisieren von Klassen vorhanden sind. Sie müssen sie selbst hinzufügen. Ob Sie es mit doppelt kontrollierter Verriegelung oder einem anderen Mechanismus tun, liegt ganz bei Ihnen.

Beginnend mit Java 8, verwende ich gerne ConcurrentHashMap#computeIfAbsent, um Faulheit zu erreichen.

class Bob { 
    private final ConcurrentHashMap<String, Jane> instance = new ConcurrentHashMap<>(1); 

    public Jane getJane() { 
     return instance.computeIfAbsent("KEY", k -> new Jane()); // use whatever constant key 
    } 
} 

Darüber hinaus gibt es für these solutions lazy Initialisierungseinrichtung ohne die gewindeSicherheitsBeschränkung. Ich war nicht in der Lage, sie für einen Multithread-Kontext sauber anzupassen.

Wie in den Kommentaren erwähnt, wird doppeltes Sperren immer schneller als diese Lösungen sein, da sie nicht alle Flaum zum Verstecken der Implementierung enthalten.

+0

Während das ist sauberer Code, wie Leistung vergleicht? –

+0

Die doppelt überprüfte Verriegelung wäre wahrscheinlich am schnellsten, da es keine zusätzlichen Überprüfungen gibt. Sie tun höchstens, was Sie tun müssen, um die Instanz zu erhalten. –

+1

Weise besser als meine ausführliche Lösung mit Guava, obwohl die Logik ähnlich ist –

2

können Sie Guava-Cache verwenden:

public class Bob { 
    private final static Object KEY = new Object(); 

    private final Cache<Object, Jane> cache = 
     CacheBuilder.newBuilder() 
        .build(new CacheLoader<Object, Jane>() { 
           @Override 
           public Jane load() { 
            return new Jane(); 
           } 
          }); 

    public Jane getJane() { 
     return cache.get(KEY); 
    } 

} 
+0

Dies ist nicht der Hauptanwendungsfall eines Caches: automatische Räumung. Eine concurrentHashMap wird die Arbeit erledigen und funktioniert gut als Guave-Cache – Zava

Verwandte Themen