В чем причина двойного вызова WeakHashMap.put (..)? - PullRequest
2 голосов
/ 05 мая 2009

Это сообщение в блоге демонстрирует способ реализации мьютекса для каждой строки с идентификатором id. Используемые строковые идентификаторы предназначены для представления идентификаторов HttpSession.

  1. Зачем нам нужно оборачивать WeakReference вокруг экземпляров Mutex? Не лучше ли просто создать карту из String -> Mutex?
  2. Зачем нам звонить пут дважды?

    public Mutex getMutex( String id )
    {                                  
        Mutex key = new MutexImpl( id );
        synchronized( mutexMap )
        {
            WeakReference<Mutex> ref = mutexMap.get( key );
            if( ref == null )
            {
                mutexMap.put( key, new WeakReference<Mutex>( key ) );
                return key;
            }
            Mutex mutex = ref.get();
            if( mutex == null )
            {
                mutexMap.put( key, new WeakReference<Mutex>( key ) );
                return key;
            }
            return mutex;
        }
    }
    

Ответы [ 4 ]

4 голосов
/ 05 мая 2009

Объекты значений в WeakHashMap хранятся обычными сильными ссылками. Таким образом, следует позаботиться о том, чтобы объекты-значения не строго ссылались на свои собственные ключи, прямо или косвенно, так как это предотвратит сброс ключей. Обратите внимание, что объект значения может косвенно ссылаться на свой ключ через сам WeakHashMap; то есть объект значения может строго ссылаться на некоторый другой ключевой объект, чей связанный объект значения, в свою очередь, строго ссылается на ключ первого объекта значения. Один из способов справиться с этим - обернуть сами значения внутри WeakReferences перед вставкой, как в: m.put (ключ, новый WeakReference (значение)), а затем распаковывать при каждом получении.

2 голосов
/ 05 мая 2009

1 - у @Loop есть хороший ответ .

2 - Предполагая, что записи заключены в WeakReferences, необходим второй put, поскольку WeakReference может быть получено до того, как выполнение достигнет строки:

 Mutex mutex = ref.get();

В этом случае:

  • запись может не существовать в map
  • если он существует, его можно собрать до выполнения Mutex mutex = ref.get();
1 голос
/ 05 мая 2009

Loop и Bruno Conde в значительной степени покрыли это, но с тех пор, как я написал этот код ...

Целью разработки было избежать вызова пользователем механизма освобождения - мьютекс может собирать мусор, когда пользователь больше не ссылается на него.

Зачем нам нужно оборачивать WeakReference вокруг экземпляров Mutex?

Карта Слабая Карта Хэша :

private final Map mutexMap = new WeakHashMap();

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

Примечание о реализации: объекты значения в WeakHashMap проводятся обычные сильные ссылки. Таким образом, забота должна быть приняты, чтобы убедиться, что объекты значения делают не сильно ссылаться на свои ключи, прямо или косвенно, так как это помешает ключам быть отбрасываются. Обратите внимание, что объект значения может косвенно ссылаться на свой ключ через сама WeakHashMap; это объект значения может сильно ссылаться на какой-то другой ключевой объект, чей связанный объект стоимости, в свою очередь, настоятельно относится к ключу первого объекта значения. Один из способов справиться с этим - обернуть сами ценят в Слабые ссылки перед вставкой, как в: m.put (ключ, новый WeakReference (значение)), а затем разворачивание при каждом получении.


Не правда ли? лучше просто создать карту из Строка -> Мьютекс?

Когда это строковое значение будет собираться мусором? Одна и та же ссылка передается каждый раз? intern () вызывается на нем? Если я позвоню стажеру, как долго будет жить String? Если ключ является строкой, мьютекс может не подходить для сборки мусора в течение долгого времени после того, как нет необходимости сохранять ссылку на него.


Зачем нам звонить пут дважды?

Необходимо обработать два случая, пока метод не сможет получить надежную ссылку на мьютекс на карте:

  • Слабая ссылка была собрана сборщиком мусора (или вообще никогда не была там)
  • содержимое WeakReference является мусором, собранным после получения ссылки на него

put будет вызываться только один раз; метод возвращается сразу после.

(Слабая ссылка может быть повторно использована во втором случае, но я не вижу, чтобы это было существенным улучшением.)


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

1 голос
/ 05 мая 2009

Я бы сказал, что WeakReference используются только потому, что они должны ссылаться на идентификаторы сессии http. Вы не всегда можете быть на 100% уверены, что получите уведомление о завершении сеанса, что приведет к постоянно растущей карте.

Первый раз, когда вы звоните, положите его, потому что на карте нет вашего ключа. Второй раз это потому, что карта содержала ключ, но ссылка больше не существовала.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...