-1

Предположим я создал коллекцию

volatile ArrayList <Integer> vo_al = new ArrayList<>();

Вопрос: Можно ли быть увереным, что когда я создам 100 потоков, которые будут читать и записывать туда значения, что потоки не попортят друг-другу память, а изменения которые внесёт один поток операцией

vo_al.add(2);

будут сразу видны всем другим потокам?

Есть ли в принципе смысл, в многопоточном программировании помечать коллекции словом volatile?

  • некоторые поля могу быть кешированы потоком в целях оптимизации. Например, вот будет у вас класс с полем int myField - возможна ситуация, что в одном потоке вы в него запишете новое значение, а после в другом птоке прочитаете старое значение, потому что другой поток поле закешировал. Чтобы такого не произошло, применяется ключепое слово volatile. Применение этого слова отменяет кеш потока, но не делает вашу структуру данных потокобезопасной. – tym32167 Sep 22 '20 at 13:48
  • Есть ли в принципе смысл, в многопоточном программировании помечать коллекции словом volatile если вы собираетесь читать эту коллекцию в разных потоках, то имеет смысл. – tym32167 Sep 22 '20 at 13:51
  • @tym32167 а запись почему не отработает атомарно? – Andrew Kachalin Sep 22 '20 at 13:57

1 Answers1

3

Конечно же нет. volatile никак не связан с объектом, который лежит по ссылке, он гарантирует, что запись и чтение переменной будет атомарно (насколько я знаю, не атомарными по записи и чтению являются только long и double) и что изменения переменной (изменение именно ссылки! а не какие-либо методы вроде add) будут сразу же видны другим потокам.

Atomic Access

Если вам нужно безопасно изменять List в нескольких потоках, то используйте Collections.synchronizedList:

List<Integer> vo_al = Collections.synchronizedList(new ArrayList<>());

Но и это не означает, что не понадобится synchronized блок или другие методы синхронизации. Например, нужно атомарно увеличить первый элемент списка на единицу. Даже с synchronizedList нужно использовать synchronized блок, так как происходит две разные операции, между которыми поток может быть остановлен или в этот момент времени произошло изменение значения из другого потока.

synchronized (vo_al) {
    vo_al.set(0, vo_al.get(0) + 1));
}

Есть ли в принципе смысл, в многопоточном программировании помечать коллекции словом volatile?

Есть, если в каком-то потоке происходит изменение ссылки.

volatile ArrayList <Integer> vo_al = new ArrayList<>();

// в одном из потоков vo_al = new ArrayList<>();

IR42
  • 4,262
  • Да спасибо, уже загуглил. Практически принято. Ссылками на АИ можете дополнить? Oracle, cайты, вики - на ваше усмотрение. Чтобы зашедшие сюда смогли быть уверены в корректности вашего ответа. – Andrew Kachalin Sep 22 '20 at 14:47
  • В ответе есть одна неточность, которая как минимум вводит в заблуждение. Речь об утверждении, что в других потоках видны изменение только в volatile переменной. Это не так. Правильно так: при чтении volatile переменной в другом потоке будут видны все результаты операций записи сделанные до записи в volatile в оригинальном потоке. – Roman-Stop RU aggression in UA Sep 22 '20 at 17:12