Объявление локальной переменной при использовании в concurrent

 
 
 
Сообщения:49
Добрый! Тема возможно сфорумлирвоана не совсем верно. Вот ситуация, блок кода из класса CopyOnWriteArrayList:
        private transient volatile Object[] array;
...
        final Object[] getArray() {
              return array;
        }
...
        public E set(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            E oldValue = get(elements, index);

            if (oldValue != element) {
                int len = elements.length;
                Object[] newElements = Arrays.copyOf(elements, len);
                newElements[index] = element;
                setArray(newElements);
            } else {
                // Not quite a no-op; ensures volatile write semantics
                setArray(elements);
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }

Вот мой вопрос - правильно понимаю, что происходит следущее:
1. Object[] elements = getArray(); - создается копия volatile поля array , именно копия внутри потока,
2. делаются манипуляции над копией там же в потоке. При этом если оригинальный array в другом потоке модифицировался, то на нашу копию elements это никак не влияет
3. после манипуляций идет запись измененного массива обратно в поле array
4. последующие обращения из других потоков уже увидят новый измененный array


Потому что если это не так, я тогда не понимаю зачем мы создаем новую ссылку на array в виде elements и через нее делаем все что нам надо, а потом делаем setArray(elements);, хотя element и так есть прямая ссылка на array. Ну по логике "обычной" java
Изменен:29 июл 2019 15:25
 
 
Сообщения:176
По второму пункту. Оригинальный array не меняется. Новые изменения делаются только в новых копиях массива array.
Quote:
Потому что если это не так, я тогда не понимаю зачем мы создаем новую ссылку на array в виде elements и через нее делаем все что нам надо, а потом делаем setArray(elements);

Это делается как раз для того, чтобы предыдущий array не модифицировать.

Для чего это делается. Допустим, у нас был получен Iterator. В итераторе будет храниться ссылка на массив array. Если CopyOnWrite будет в дальнейшем модифицирован, то Iterator эти действия не затронут, т.к. он будет работать со старой версия array.
Проще наверно это кодом показать.

        List<Integer> list = new CopyOnWriteArrayList<>(Arrays.asList(1,2,3));
        Iterator<Integer> iter = list.iterator();
        list.clear();

        while (iter.hasNext()) {
            System.out.println(iter.next());
        }

Вывод:
1
2
3


Также мы можем модифицировать CopyOnWriteArrayList в цикле for in
    public static void main(String[] args) {
        List<Integer> list = new CopyOnWriteArrayList<>(Arrays.asList(1,2,3));
        for (Integer el : list) {
            list.remove(el);
        }
        System.out.println(list.size());
    }

Вывод
0


Попробуем это проделать с ArrayList
        List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3));
        for (Integer el : list) {
            list.remove(el);
        }
        System.out.println(list.size());

Вывод
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
	at java.util.ArrayList$Itr.next(ArrayList.java:859)
	at javatalks.CopyOnWriteDemo.main(CopyOnWriteDemo.java:22)
 
 
Сообщения:49
axwer, спасибо

Просто странность (для меня :) ) в том, что обычно вызов Object[] elements = getArray() дает переменной elements ссылку непосредственно на array, ну то есть по сути Object[] elements = array
Но в данном случае из-за того, что elements это локальная переменная в другом потоке (а может и в том же - если однопоток), JVM включает дополнительный механизм (копирования) и снимает с array его копию и уже на ЭТУ копию дает ссылку для elements , верно ?

А кстати как размышление - а это никак нельзя использовать для копирования или даже глубокого копирования объектов ?
Изменен:30 июл 2019 07:46
 
 
Сообщения:176
Quote:
и уже на ЭТУ копию дает ссылку для elements

По коду он уже даёт ссылку на newElements. И потом array будет ссылаться на newElements.

Quote:
А кстати как размышление - а это никак нельзя использовать для копирования или даже глубокого копирования объектов ?

Глубокое копирование врятли. Копирование думаю можно, но зачем. Стороннему человеку трудно будет понять потом такой код. Да и сам потом ужаснешься, когда увидишь этот код через некоторое время.
Изменен:30 июл 2019 08:37
 
Модераторы:frymock
Сейчас эту тему просматривают:Нет