Главная » Java » Очереди ссылок Java

0

 

   Когда стадия достижимости объекта меняется, он может быть помещен в очередь ссылок (reference queue). Такие очереди используются сборщиком мусора для взаимодействия с прикладной программой при изменении стадий достижимости объектов. Это наилучший способ выявления подобных изменений, хотя иногда можно применять и средства явного опроса объектов.

   Предположим, что необходимо создать хеш-таблицу, в которой значения представляются с помощью объектов слабых ссылок, — в отличие от WeakHashMap, где такие объекты используются для задания ссылок на ключи. Подобная хеш-таблица должна помочь в установлении связи между ключами, объекты которых подвержены частым изменениям, и соответствующими значениями. Например, таким образом можно ассоциировать местоположение класса с соответствующим загрузчиком классов (см. раздел 11.3 на странице 319). Каждый раз при необходимости загрузки нового класса, размещенного по одному и тому же адресу в файловой системе, следует использовать тот же загрузчик классов. Положение класса описывается небольшим объектом типа String или File, который нетрудно создать заново для каждого нового класса, нуждающегося в загрузке. Загрузчик классов, с другой стороны, — это крупный объект, содержащий многочисленные ссылки на другие объекты и подлежащий утилизации, если ссылки на него отсутствуют. Если для задания связи между объектом-ключом, описывающим местоположение кода класса, и объектом загрузчика классов использовать средства WeakHashMap, будет получен обратный эффект: всякий раз когда загрузка класса не выполняется, ключ может оказаться удаленным.

  Приведенный ниже код предполагает создание хеш-таблицы со "слабыми значениями", основанной на использовании очереди ссылок, которая позволяет зафиксировать факт перехода значения на стадию слабой достижимости. Когда значение, принадлежащее конкретной паре ключ/значение, становится слабо достижимым, соответствующая связь из таблицы удаляется, после чего ключ может быть утилизирован сборщиком мусора (разумеется, если иных ссылок на этот объект не существует).

 

 

 

import java.1ang.ref.*;

import java.until.*;

public class weakvalиемар extends HashMap {

 private  ReferenceQueue  reaped = new ReferenceQueueO;

 private static class valueRef extends weakReference {

private final  object key;       // Ключ

valueRef(Object val,  Object key,   ReferenceQueue q)   {

super(val,   q);

   this.key = key;

  }

}

public object put(Object key,  Object value)   {

reapO ;

valueRef vr = new valueRef(value, key, reaped);

   return super.put(key, vr);

 }

 

public Object getCobject key)  {

 reapO ;

ValueRef vr =  (valueRef)super.get(key);

 return vr = = null   ?  null   :   vr.getO;

public  int  size()   {

 reap();

 return super.size();

}

//   …   Реализация других методов мар   …

public void  reapO   {

 valueRef ref;

while  ((ref = (valueRef)reaped.poll())   != null)

 super.remove(ref.key);

 }

}

WeakValueMap — это класс, производный от HashMap, в котором для связи со значениями используются объекты собственного вложенного класса ValueRef, расширяющего WeakReference. Когда значение становится слабо достижимым, соответствующий ему объект ValueRef помещается в очередь reaped. Каждая операция, выполняемая с таблицей, начинается с вызова метода reap, который удаляет из таблицы любые элементы, ссылки на которые содержатся в очереди. Объекты ключей, отвечающие удаленным значениям, таблицей более не адресуются, поэтому они могут быть утилизированы сборщиком мусора, если иные ссылки на них отсутствуют. Конечно, применять средства WeakReference для ссылки на объекты, которые всегда прочно достижимы — такие как активные объекты Threads потоков вычислений, — вряд ли целесообразно.

   Как отмечено в комментариях к коду, полная реализация класса WeakValueMap должна содержать переопределенные — по аналогии с put и get — варианты всех методов HashMap, которые имеют дело с ключами таблицы.

   В составе класса ReferenceQueue существуют три метода, предназначенных для удаления элементов очереди.

 public Reference poilO

Удаляет из очереди очередной объект-ссылку и возвращает его; если очередь пуста, возвращается значение null.

 public Reference remove()  throws interrupredException

Удаляет из очереди очередной объект-ссылку и возвращает его; вызов метода блокирует выполнение потока на неопределенное время, пока очередь остается непустой.

public  Reference  remove(long timeout)  throws  interrupredException.

 Удаляет из очереди очередной объект-ссылку и возвращает его; вызов метода блокирует выполнение потока на неопределенное время, пока очередь остается непустой либо не подошел к концу промежуток времени, заданный параметром  timeout;   по  истечении  периода  timeout  возвращается

 

null; при задании в качестве timeout нулевого значения блокировка устанавливается на неопределенное время.

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

   Метод poll позволяет потоку запросить информацию о наличии ссылок в очереди и действует только в том случае, если очередь не пуста, как показано в тексте метода reap. Методы remove предназначены для использования в более сложных (и редких) ситуациях, когда за удаление ссылок и выполнение дальнейших действий несет ответственность специально выделенный для этой цели поток вычислений; поведение метода, касающееся блокирования работы потока, схоже с тем, которое демонстрирует, например, метод Object.wait (см. раздел 10.4 на странице 259). Сведения о том, присутствует ли в очереди определенный объект-ссылка, легко получить посредством метода isEnqueued этого объекта, который, однако, объект из очереди не удаляет. Объект можно принудительно поместить в очередь, вызвав его метод enqueue, хотя обычно эта функция выполняется сборщиком мусора.

   Очереди ссылок работают и с номинальными ссылками, позволяя определить, когда объект готов к утилизации. Номинальная ссылка никогда не позволяет достичь объекта — даже в том случае, если он достижим иными средствами, — поскольку метод get всегда возвращает null. Номинальные ссылки — это и безопасное средство представления информации об утилизируемых объектах; слабая или легкая ссылка помещается в очередь после того, как адресуемый ею объект переходит на стадию I достижимости в процессе finalize. Номинальная ссылка заносится в очередь после  выполнения операции firialize адресуемого объекта и, следовательно, по прошествии самого последнего момента времени, когда объект еще способен выполнять какие-либо действия. По возможности следует анализировать именно номинальные ссылки, поскольку ссылки других типов оставляют за методом finalize право использования объектов тем или иным образом.

   Номинальная ссылка, будучи размещенной в очереди, не очищается, и поэтому адресуемый ею объект не может быть утилизирован до тех пор, пока ссылка не будет очищена либо не потеряет свойство достижимости.

   Упражнение 12.2. Завершите реализацию класса WeakValueMap таким образом, чтобы все методы, имеющие дело со значениями, работали верно. Не забудьте воспользоваться объектами итераторов и уделите особое внимание ситуации, когда метод hasNext возвращает значение true. (Это упражнение повышенной сложности, поскольку требует знания классов коллекций итераторов, — за соответствующей информацией обращайтесь к главе 16.)

Упражнение 12.3. Перепишите класс weakValueMap в PhantomValueMap.

 

Источник: Арнолд, Кен, Гослинг, Джеймс, Холмс, Дэвид. Язык программирования Java. 3-е изд .. : Пер. с англ. – М. : Издательский дом «Вильяме», 2001. – 624 с. : ил. – Парал. тит. англ.

По теме:

  • Комментарии