Как сделать поток кеша безопасным - PullRequest
1 голос
/ 22 декабря 2011

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

Так что в первом случае я создаю экземпляр и сохраняю его в своем собственном пользовательском кэше.

Со следующих раз, что угоднопоток приходит, если он обнаруживает, что готовый объект уже присутствует в кеше, они берут его из кеша, чтобы обеспечить хорошую производительность.

Меня беспокоило, что, если два потока имеют один и тот же экземпляр.Есть ли вероятность, что два потока могут испортить друг друга.

 Map<String, SoftReference<CacheEntry<ClassA>>> AInstances= Collections.synchronizedMap(new HashMap<String, SoftReference<CacheEntry<ClassA>>>());

Ответы [ 4 ]

0 голосов
/ 22 декабря 2011

Если у вас есть только один экземпляр объекта, взгляните на:

Потокобезопасный кэш одного объекта в Java

В противном случае я не могу порекомендовать библиотеку gava гуавы , особенно посмотрите на класс MapMaker .

0 голосов
/ 22 декабря 2011

Есть много возможных решений:

  • Используйте существующее решение для кэширования, например EHcache
  • Используйте среду Spring, которая позволяет легко кэшировать результаты метода с помощью простой @ Cacheable аннотации
  • Используйте одну из синхронизированных карт, например ConcurrentHashMap
  • Если вы знаете все ключи заранее, вы можете использовать Ленивый код инициализации . Обратите внимание, что все в этом коде есть причина; измените что-либо в get(), и это в конечном итоге сломается (в конце концов == "ваши модульные тесты будут работать, и он будет работать без перебоев после годичного производства").

ConcurrentHashMap проще всего настроить, но в нем есть простой способ сказать «инициализировать значение ключа один раз».

Не пытайтесь самостоятельно реализовать кэширование; Многопоточность в Java стала очень сложной областью с Java 5 и появлением многоядерных процессоров и барьеров памяти.

[РЕДАКТИРОВАТЬ] Да, это может произойти, даже если карта синхронизирована. Пример:

SoftReference<...> value = cache.get( key );
if( value == null ) {
    value = computeNewValue( key );
    cache.put( key, value );
}

Если два потока запускают этот код одновременно, computeNewValue() будет вызван дважды. Вызовы методов get() и put() безопасны - несколько потоков могут пытаться выполнить одновременно, и ничего плохого не произойдет, но это не защитит вас от проблем, возникающих при последовательном вызове нескольких методов и состояние карты не должно меняться между ними.

0 голосов
/ 22 декабря 2011

Хорошо. Если я правильно понимаю вашу проблему, вы беспокоитесь, что 2 объекта, изменяющих состояние общего объекта, повредят друг друга.

Короткий ответ: да, они будут.

Если объект дорог в создании, но нужен только для чтения. Я предлагаю вам сделать его неизменным, так вы получите преимущество, заключающееся в быстром доступе и в то же время безопасном потоке.

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

Наконец, если ваш объект должен быть доступен для записи и совместного использования (по другим причинам, кроме того, что он просто дорогой для создания). Тогда, мой друг, тебе нужно заботиться о безопасности потоков, я не знаю твоего случая, но ты должен взглянуть на синхронизированное ключевое слово, функции одновременного блокирования и Java 5, атомарные типы. Я уверен, что один из них удовлетворит вашу потребность, и я искренне желаю, чтобы ваше дело было одним из первых 2:)

0 голосов
/ 22 декабря 2011

Если вы говорите о синглетах, просто используйте " требование к идиоме держателя инициализации ", чтобы убедиться, что ваш "чек" работает во всех JVM. Это также гарантирует, что все потоки, которые одновременно запрашивают один и тот же объект, ожидают окончания инициализации и возвращают только действительный экземпляр объекта.

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

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