簡體   English   中英

Java SoftReference奇怪的行為

[英]Java SoftReference strange behaviour

Map<E, SoftReference<T>> cache = new ConcurrentHashMap<E, SoftReference<T>>();

我有地圖聲明了一個像我上面用作Cache的地圖。

問題是我將項目添加到緩存后立即執行緩存上的所有操作,但不是稍后。

例如:

cache.add("Username", "Tom");

if(cache.contains("Username"))返回true但是

String userName = (String)cache.get("Username")返回null。

這種情況只在很長一段時間后發生。

如果我在將它添加到緩存幾個小時后得到該值,我會正確獲得該值。 如果我在很長一段時間后得到這個值,比如超過15-20小時,我就會得到null。

當GC清除SoftReference對象時,密鑰是否仍保留在HashMap中? 這是出現這種行為的原因嗎?

SoftReference被垃圾收集時, SoftReference清除 ,即它的引用字段被設置為null

因此,不僅密鑰保留在地圖中,相關的值SoftReference實例也會保留在地圖中,即使其引用字段為null

但是因為在你聲明的Map<E, SoftReference<T>>字段和cache.add("Username", "Tom")(String)cache.get("Username")的調用者之間必須有一個層,你沒有展示,甚至可能是這個圖層正確處理它的情況。

為了完整起見,正確的實現可能看起來像

final Map<E, SoftReference<T>> cache = new ConcurrentHashMap<>();

/** remove all cleared references */
private void clean() {
    cache.values().removeIf(r -> r.get() == null);
}
public void add(E key, T value) {
    clean();
    cache.put(key, new SoftReference<>(value));
}
public boolean contains(E key) {
    clean();
    return cache.computeIfPresent(key, (e,r) -> r.get()==null? null: r) != null;
}
public T get(E key) {
    clean();
    for(;;) {
        SoftReference<T> ref = cache.computeIfPresent(key, (e,r) -> r.get()==null? null: r);
        if(ref == null) return null;
        T value = ref.get();
        if(value != null) return value;
    }
}

此代碼確保在查詢時以原子方式刪除收集值的映射。 此外,雖然不是必需的,但clean()操作會刪除所有收集的地圖條目,以減少地圖的空間(與WeakHashMap內部工作方式相當)。

但請注意,仍然沒有保證當cache.contains("Username")返回true ,后續的cache.get("Username")將返回非null值。 這個問題也稱為check-then-act反模式,它可能會失敗,因為在檢查和后續操作之間,可能會發生並發更新(這里即使你只使用一個線程的緩存,垃圾收集可能是異步發生的),過時的測試結果已經過時了。

在這方面,對於大多數情況, contains操作是無用的。 您必須調用get ,以接收對值的強引用,並繼續該引用(如果為非null

按照oracle文檔

在虛擬機拋出OutOfMemoryError之前,保證已清除對軟可訪問對象的所有軟引用。

是當GC清除SoftReference對象時,該鍵保留在HashMap中。 除了它們在地圖內部之外,鍵和相應的值沒有任何關系。 map's value設為普通參考map's value ,除非地圖為GC,否則它們將始終位於地圖中。

是的,這是正常的行為。

SoftReference被垃圾收集,導致Map中的值被設置為null

對於其他類型的地圖(例如,地圖),將某個鍵的值設置為null是相同的

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM