Подтвердить что ты не робот

Многопотоковое присвоение атомных ссылок Java

У меня есть кеш, который я реализовал с помощью simeple HashMap. как -

HashMap<String,String> cache = new HashMap<String,String>();

Этот кеш используется большую часть времени для чтения значений из него. У меня есть другой метод, который перезагружает кеш и внутри этого метода. Я в основном создаю новый кеш и затем назначаю ссылку. Насколько я понимаю, назначение объектной ссылки - это Atomic в Java.

public class myClass {
     private HashMap<String,String> cache = null;
    public void init() {
       refreshCache();
    }
    // this method can be called occasionally to update the cache.
    public void refreshCache() {
        HashMap<String,String> newcache = new HashMap<String,String>();
       // code to fill up the new cache
       // and then finally
       cache = newcache; //assign the old cache to the new one in Atomic way
    }
}

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

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

Edit- Моя основная путаница в том, что мне не нужно использовать AtomicReference здесь, поскольку сама операция назначения является атомарной?

РЕДАКТИРОВАТЬ - Я понимаю, что для правильного упорядочения я должен отметить кеш как изменчивый. Но если метод refreshCache отмечен как синхронизированный, мне не нужно делать кеш изменчивым, так как синхронизированный блок будет заботиться о порядке и видимости?

4b9b3361

Ответ 1

Он не безопасен без надлежащего барьера памяти.

Можно подумать, что назначение кеша (cache = newCache) произойдет после шагов по заполнению кеша. Тем не менее, другие потоки могут пострадать от переупорядочения этих операторов, чтобы, возможно, назначение могло произойти до заполнения кеша. Таким образом, можно получить новый кеш, прежде чем он будет полностью сконструирован или, что еще хуже, увидеть исключение ConcurrentModificationException.

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

Ответ 2

Вы должны пометить кеш как volatile.

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

В порядке предпочтения (в основном из-за удобочитаемости):

  • Обновить поле в синхронизированном методе
  • Используйте AtomicReference<Map<>>
  • Используйте volatile

См. также question.

Ответ 3

Как насчет коллекций CopyOnWrite..

java.util.concurrent.CopyOnWriteArraySet
java.util.concurrent.CopyOnWriteArraySet
and org.apache.mina.util.CopyOnWriteMap

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

Ответ 4

Кажется, все в порядке. Убедитесь, что refreshCache не вызывается слишком часто или отмечен как synchronized.