Создание объекта видимым для других до завершения его конструктора не является потокобезопасным.
Не ясно, как карта используется в этом случае, но предположим, что в классе есть такой статический метод, как этот:
public static DataEntry getEntry(String name) {
return _INTERNAL_LIST.get(name);
}
Другой поток, работающий одновременно, может получить доступ к DataEntry
во время его создания и начать использовать запись с неинициализированным VALUE
. Даже если вы переупорядочите код в конструкторе так, чтобы добавление нового экземпляра на карту было последним, что вы делаете, JVM разрешается переупорядочивать инструкции, чтобы объект был добавлен в список первым. Или, если класс расширен, инициализация подкласса может иметь место после публикации объекта.
Если более одного потока получает доступ к взаимодействиям с классом DataEntry
, вы можете столкнуться с ошибкой параллелизма, которая зависит от платформы, периодически и очень сложно диагностировать.
Статья Брайана Гетца «Безопасное строительство» содержит больше информации по этой теме.
Возвращаясь к первоначальному вопросу: использование WeakReference
, как уже упоминалось другими, является хорошим подходом, но вместо того, чтобы перебирать каждую запись на карте, я бы рекомендовал создать оболочку для ваших значений, которая расширяет WeakReference
(это может быть ваш DataEntry
сам или помощник) и помещать в очередь каждую ссылку в ReferenceQueue
. Таким образом, вы можете быстро опросить очередь на предмет любых собранных записей и удалить их с карты. Это может быть выполнено фоновым потоком (блокировка remove
), запущенным в инициализаторе класса, или любые устаревшие записи могут быть очищены ( опросом ) каждый раз, когда новая запись добавлено.
Если ваша программа многопоточная, вы должны отказаться от LinkedHashMap
для карты с java.util.concurrent
или обернуть LinkedHashMap
с Collections.synchronizedMap()
.