Когда референт SoftReference
получает мусор, SoftReference
получает очищенный , т. Е. Его поле референта устанавливается на null
.
Так что не толькоПри нажатии клавиши key на карте соответствующее значение, экземпляр SoftReference
, также остается на карте, даже если его референтное поле равно null
.
Но поскольку между объявленным * 1012 должен быть слой* field и вызывающая сторона 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")
вернет не-1027 * значение.Эта проблема также известна как анти-шаблон check-then-act , который может завершиться ошибкой, поскольку между проверкой и последующим действием может происходить параллельное обновление (здесь, даже если вы используете кэштолько один поток, так как сборка мусора может происходить асинхронно), устарел результат предыдущего теста.
В этом отношении операция contains
бесполезна для большинства сценариев.Вы должны вызвать get
, чтобы получить сильную ссылку на значение, и продолжить работу с этой ссылкой, если не- null
.