Установление Happens-Before в массивах

Есть быстрый вопрос синхронизации, вот что у меня есть:

а) Class1 имеет параллельную хеш-карту, определенную следующим образом:

ConcurrentMap<String, int[][]> map  = new ConcurrentHashMap<String, int[][]>();

б) Class2 имеет поток с именем Thread1. Thread1 создает Id и проверяет, содержит ли его map. Если это так, он извлекает значение (int[][]), изменяет содержимое и возвращает его обратно. Если это не так, он создает новый int[][] и сохраняет его. Этот процесс проверки->изменения/создания происходит часто.

 private class Thread1 implements Runnable{

            public void run(){
                //keepRunning is volatile
                while( keepRunning ){

                  String id     = "ItemA";
                  int[][] value = map.get(id);

                  //If value is null, create an int[][] and put it back as value for Id
                  //If value is not null, modify the contents according to some logic  
                 }
             }
    }

c) Наконец, у меня есть еще один поток, который называется Thread2. Этот поток принимает идентификатор, проверяет, имеет ли карта значение для него. Если это не так, ничего не происходит. Если это так, то он суммирует значения в int[][] и использует число для некоторых вычислений (здесь никаких изменений).

Я пытаюсь выяснить, являются ли мои операции атомарными. Операции в b) выполняются нормально, так как создание/изменение массива и вставка в карту ограничены только одним потоком (Thread1).

Кроме того, поскольку вставка в карту устанавливает действие «происходит до», это гарантирует, что c) увидит обновленные значения в int[][].

Однако я не слишком уверен в том, что произойдет, если Thread2 будет искать тот же самый int[][] на карте и попытается суммировать его, пока Thread1 изменяет его.

Правильно ли я думаю, что Thread2 увидит старые (но неповрежденные) значения в int[][]. Причина в том, что пока Thread1 не закончит возвращать значение в карту, новые изменения не будут видны Thread2.

Большое спасибо.


person CaptainHastings    schedule 04.08.2012    source источник
comment
Как примечание, вы, вероятно, знаете об этом, но похоже, что вы пытаетесь реализовать шаблон Producer/Consmer, взгляните на docs.oracle.com/javase/tutorial/essential/concurrency/, чтобы узнать больше   -  person MadProgrammer    schedule 04.08.2012


Ответы (1)


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

Чтобы избежать этого, вам нужно будет дублировать оригинал, изменить дубликат и вернуть копию.

person Tom    schedule 04.08.2012
comment
Привет, Том, спасибо. В качестве альтернативы, могу ли я не а) использовать AtomicReferenceArray б) создать новый массив в б) (вместо того, чтобы получать старый массив из карты), а затем обновить карту с ним для определенного идентификатора. - person CaptainHastings; 06.08.2012