Понимание классов Java Reference: SoftReference, WeakReference и PhantomReference

Может кто-нибудь объяснить разницу между тремя классами Reference (или отправить ссылку на хорошее объяснение)? SoftReference > WeakReference > PhantomReference, но когда я буду использовать их? Почему существует WeakHashMap, но не SoftHashMap или PhantomHashMap?

И если я использую следующий код...

WeakReference<String> ref = new WeakReference<String>("Hello!");
if (ref != null) {                 // ref can get collected at any time...
    System.gc();                   // Let assume ref gets collected here.
    System.out.println(ref.get()); // Now what?!
}

... что происходит? Должен ли я проверять, является ли ref значением null перед каждым утверждением (это неправильно, но что мне делать)? Извините за вопросы быстрого огня, но мне трудно понять эти классы Reference... Спасибо!

Ответ 1

Документация библиотеки Java для пакета java.lang.ref характеризует уменьшающуюся прочность трех явных ссылочных типов.

Вы используете SoftReference, когда хотите, чтобы объект, на который ссылался, оставался в живых, пока хост-процесс не работает на памяти. Объект не будет иметь права на сбор до тех пор, пока сборщик не захочет освободить память. Неясно сказано, привязка a SoftReference означает: "Зацепите объект, пока не сможете больше".

В отличие от этого, используйте WeakReference, если вы не хотите влиять на время жизни объекта ссылки; вы просто хотите сделать отдельное утверждение об упомянутом объекте, пока оно остается живым. На доступность объекта для сбора не влияет присутствие связанных WeakReference s. Что-то вроде внешнего сопоставления из экземпляра объекта в связанное свойство, где свойство нужно записывать только до тех пор, пока родственный объект жив, полезно использовать для WeakReference и WeakHashMap.

Последний - PhantomReference - сложнее охарактеризовать. Подобно WeakReference, такая привязка PhantomReference не влияет на время жизни ссылочного объекта. Но в отличие от других ссылочных типов, нельзя даже разыменовать a PhantomReference. В некотором смысле, он не указывает на то, на что он указывает, насколько могут сказать абоненты. Он просто позволяет связать некоторые связанные данные с указанными объектами - данными, которые впоследствии могут быть проверены и обработаны, когда PhantomReference окажется в очереди в связанном с ним ReferenceQueue. Обычно выводится тип из PhantomReference и включает некоторые дополнительные данные в этот производный тип. К сожалению, существует некоторое понижение, чтобы использовать такой производный тип.

В вашем примере кода это не ссылка ref (или, если хотите, "переменная" ), которая может быть нулевой. Скорее, это значение получается путем вызова Reference#get(), который может быть нулевым. Если он окажется равным нулю, вы опоздаете; ссылочный объект уже находится на пути к его сбору:

final String val = ref.get();
if (null != val)
{
  // "val" is now pinned strongly.
}
else
{
  // "val" is already ready to be collected.
}

Ответ 2

Ссылка: https://community.oracle.com/blogs/enicholas/2006/05/04/understanding-weak-references

PhantomHashMap не будет работать очень хорошо, поскольку get всегда возвращает null для ссылок phantom.

Кэши сложны, поэтому SoftHashMap может не работать так хорошо, как вы могли бы подумать. Тем не менее, я считаю, что библиотека коллекции Google содержит общую реализацию эталонной карты.

Вы всегда должны проверить, что get возвращает не null. (Обратите внимание, что не проверка того, что сама ссылка Reference не является <<22 > ). В случае интернированных строк она всегда будет, но (как всегда) не пытается быть "умной" об этом.

Ответ 4

    String str = new String("hello, world");
    WeakReference<String> ref = new WeakReference<String>(str);
    str = null;
    if (ref != null) {                 
        System.gc(); 
        System.out.println(ref.get());
    }

В этом случае он выведет нуль. Здесь важна System.gc().