From 5232057b153edbd8b24aef31cd2a57901ebee62e Mon Sep 17 00:00:00 2001 From: "J. Neugebauer" Date: Mon, 12 Dec 2022 21:26:24 +0100 Subject: [PATCH] SoftCache zu Cache generalisiert Ein Cache kann nun auch mit `WeakReference`n genutzt werden. --- .../zm/util/{SoftCache.java => Cache.java} | 68 +++++++++++++++---- .../schule/ngb/zm/util/io/FontLoader.java | 3 +- .../schule/ngb/zm/util/io/ImageLoader.java | 5 +- 3 files changed, 60 insertions(+), 16 deletions(-) rename src/main/java/schule/ngb/zm/util/{SoftCache.java => Cache.java} (57%) diff --git a/src/main/java/schule/ngb/zm/util/SoftCache.java b/src/main/java/schule/ngb/zm/util/Cache.java similarity index 57% rename from src/main/java/schule/ngb/zm/util/SoftCache.java rename to src/main/java/schule/ngb/zm/util/Cache.java index 08c985b..d17b3f7 100644 --- a/src/main/java/schule/ngb/zm/util/SoftCache.java +++ b/src/main/java/schule/ngb/zm/util/Cache.java @@ -1,19 +1,63 @@ package schule.ngb.zm.util; +import java.lang.ref.Reference; import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; import java.util.stream.Collectors; -public class SoftCache implements Map { +/** + * Ein Cache ist ein {@link Map} Implementation, die Inhaltsobjekte in einer + * {@link Reference} speichert und als Zwischenspeicher für Objekte dienen kann, + * deren Erstellung aufwendig ist. + *

+ * Für einen Cache ist nicht garantiert, dass ein eingefügtes Objekt beim + * nächsten Aufruf noch vorhanden ist, da die Referenz inzwischen vom Garbage + * Collector gelöscht worden sein kann. + *

+ * Als interne Map wird einen {@link ConcurrentHashMap} verwendet. + * + * @param Der Typ der Schlüssel. + * @param Der Typ der Objekte. + */ +public final class Cache implements Map { - private final Map> cache = new ConcurrentHashMap<>(); + /** + * Erstellt einen Cache mit {@link SoftReference} Referenzen. + * + * @param Der Typ der Schlüssel. + * @param Der Typ der Objekte. + * @return Ein Cache. + */ + public static Cache newSoftCache() { + return new Cache<>(SoftReference::new); + } - private final SoftReference NOCACHE = new SoftReference<>(null); + /** + * Erstellt einen Cache mit {@link WeakReference} Referenzen. + * + * @param Der Typ der Schlüssel. + * @param Der Typ der Objekte. + * @return Ein Cache. + */ + public static Cache newWeakCache() { + return new Cache<>(WeakReference::new); + } - public SoftCache() { + + private final Map> cache = new ConcurrentHashMap<>(); + + private final Reference NOCACHE; + + private final Function> refSupplier; + + private Cache( Function> refSupplier ) { + this.refSupplier = refSupplier; + NOCACHE = refSupplier.apply(null); } @Override @@ -26,6 +70,10 @@ public class SoftCache implements Map { return cache.isEmpty(); } + private boolean containsRef( Object key ) { + return cache.containsKey(key); + } + @Override public boolean containsKey( Object key ) { return cache.containsKey(key) && cache.get(key).get() != null; @@ -37,10 +85,6 @@ public class SoftCache implements Map { .anyMatch(( ref ) -> ref.get() != null && ref.get() == value); } - private boolean containsRef( Object key ) { - return cache.containsKey(key); - } - @Override public V get( Object key ) { if( cache.containsKey(key) ) { @@ -61,7 +105,7 @@ public class SoftCache implements Map { public V put( K key, V value ) { if( !isNocache(key) ) { V prev = remove(key); - cache.put(key, new SoftReference<>(value)); + cache.put(key, refSupplier.apply(value)); return prev; } else { return null; @@ -70,7 +114,7 @@ public class SoftCache implements Map { @Override public V remove( Object key ) { - SoftReference ref = cache.get(key); + Reference ref = cache.get(key); cache.remove(key); V prev = null; @@ -129,12 +173,12 @@ public class SoftCache implements Map { @Override public V getValue() { - return SoftCache.this.get(key); + return Cache.this.get(key); } @Override public V setValue( V value ) { - return SoftCache.this.put(key, value); + return Cache.this.put(key, value); } } diff --git a/src/main/java/schule/ngb/zm/util/io/FontLoader.java b/src/main/java/schule/ngb/zm/util/io/FontLoader.java index bb0b327..997d5bb 100644 --- a/src/main/java/schule/ngb/zm/util/io/FontLoader.java +++ b/src/main/java/schule/ngb/zm/util/io/FontLoader.java @@ -1,5 +1,6 @@ package schule.ngb.zm.util.io; +import schule.ngb.zm.util.Cache; import schule.ngb.zm.util.Log; import schule.ngb.zm.util.Validator; @@ -22,7 +23,7 @@ import java.util.concurrent.ConcurrentHashMap; */ public class FontLoader { - private static final Map fontCache = new ConcurrentHashMap<>(); + private static final Cache fontCache = Cache.newSoftCache(); /** * Lädt eine Schrift aus einer Datei. diff --git a/src/main/java/schule/ngb/zm/util/io/ImageLoader.java b/src/main/java/schule/ngb/zm/util/io/ImageLoader.java index 1611cea..9605440 100644 --- a/src/main/java/schule/ngb/zm/util/io/ImageLoader.java +++ b/src/main/java/schule/ngb/zm/util/io/ImageLoader.java @@ -1,7 +1,7 @@ package schule.ngb.zm.util.io; import schule.ngb.zm.util.Log; -import schule.ngb.zm.util.SoftCache; +import schule.ngb.zm.util.Cache; import schule.ngb.zm.util.Validator; import javax.imageio.ImageIO; @@ -17,7 +17,6 @@ import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReference; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; /** * Eine Helferklasse mit Klassenmethoden, um Bilder zu laden. @@ -30,7 +29,7 @@ public final class ImageLoader { public static boolean caching = true; - private static final SoftCache imageCache = new SoftCache<>(); + private static final Cache imageCache = Cache.newSoftCache(); /** * Lädt ein Bild von der angegebenen Quelle {@code source}.