Два предоставленных вами фрагмента кода отлично , как они есть.То, что вы сделали, похоже на то, как ленивое создание экземпляров с помощью MapMaker.makeComputingMap () в Guava может работать, но я не вижу проблем с тем, как лениво создаются ключи.
You 'верно то, что поток может быть предварительно выгружен после поиска get()
объекта блокировки, но до входа в синхронизированный.
Myпроблема с третьим пунктом в описании вашей расы.Вы говорите:
поток 2: удаляет объект с карты, выходит из синхронизированного блока
Какой объект и какая карта?В общем, я предположил, что вы искали ключ для блокировки, а затем выполняли некоторые другие операции над другими структурами данных в синхронизированном блоке.Если вы говорите об удалении объекта блокировки из ConcurrentHashMap, упомянутого в начале, это огромное различие.
И реальный вопрос в том, нужно ли это вообще.В среде общего назначения я не думаю, что возникнут какие-либо проблемы с памятью, если вспомнить все объекты блокировки для всех ключей, которые когда-либо просматривались (даже если эти ключи больше не представляют живые объекты).На намного сложнее придумать какой-нибудь способ безопасного удаления объекта, который может быть сохранен в локальной переменной какого-либо другого потока в любое время, и если вы действительно хотите пойти по этому пути, у меня естьощущение, что производительность ухудшится по сравнению с одним грубым замком вокруг поиска ключа.
Если я неправильно понял, что там происходит, не стесняйтесь меня поправлять.
Редактировать: ОК - в этом случае я придерживаюсь своего утверждения, что самый простой способ сделать это - не удалить ключи;на самом деле это может быть не так проблематично, как вы думаете, так как скорость роста пространства будет очень мала.По моим расчетам (что может быть не так, я не эксперт в космических расчетах, и ваша JVM может отличаться) карта увеличивается примерно на 14 КБ / час.Вам понадобится год непрерывной работы, прежде чем эта карта израсходует 100 МБ пространства кучи.
Но давайте предположим, что ключи действительно нужно удалить.Это создает проблему, заключающуюся в том, что вы не можете удалить ключ, пока не узнаете, что ни один из потоков не использует его.Это приводит к проблеме "курицы и яйца", когда вам нужно будет синхронизировать все потоки на чем-то иначе , чтобы получить атомарность (проверки) и видимость между потоками, что затем означает, что вы не можетеДелайте гораздо больше, чем шлепайте один синхронизированный блок вокруг всего, полностью подрывая вашу стратегию чередования блокировок.
Давайте вернемся к ограничениям.Главное здесь, чтобы все прояснилось со временем .Это не ограничение правильности, а просто проблема с памятью.Следовательно, что мы действительно хотим сделать, это определить некоторую точку, в которой ключ определенно больше не может быть использован, а затем использовать это как триггер, чтобы удалить его с карты.Здесь есть два случая:
- Вы можете идентифицировать такое состояние и логически проверить его.В этом случае вы можете удалить ключи с карты с (в худшем случае) каким-то потоком таймера или, надеюсь, с некоторой логикой, которая более четко интегрирована с вашим приложением.
- Вы не можете определить какое-либо условие, с помощью которого вы знать , что ключ больше не будет использоваться.В этом случае, по определению, нет точки, в которой можно безопасно удалить ключи с карты.Так что на самом деле, ради правильности, вы должны оставить их внутри.
В любом случае это фактически сводится к ручному сбору мусора.Удалите ключи с карты, когда вы можете лениво определить, что они больше не будут использоваться.Ваше текущее решение здесь слишком нетерпеливо, поскольку (как вы указали) оно выполняет удаление до того, как эта ситуация сохранится.