Синхронизация в Java — Vector vs ArrayList

Я пытаюсь понять разницу между классами Vector и ArrayList с точки зрения потокобезопасности. Vector предположительно внутренне синхронизирован. Синхронизируется ли он по каждому элементу или в целом? (Я мог бы представить себе случай, когда несколько потоков могут получить доступ к вектору одновременно, но несколько потоков не могут одновременно получить доступ к одному и тому же элементу). Если вы посмотрите на приведенный ниже код, getAo() не эквивалентен getV(), потому что ключевое слово synchronized при использовании в сигнатуре метода синхронизируется с содержащим его объектом класса (экземпляром VectorVsArrayList), насколько мне известно. ОДНАКО, getAoSync() эквивалентно getV()? Под эквивалентом я подразумеваю, начинает ли переменная экземпляра ao вести себя как объект Vector с точки зрения синхронизации, если весь доступ к нему осуществляется через метод получения?

public class VectorVsArrayList {

        private ArrayList<?> ao = null;
        private Vector<?> v = null;



        public ArrayList<?> getAoSync(){
            synchronized(ao){
                return ao;
            }
        }


        public synchronized ArrayList<?> getAo() {
            return ao;
        }


        public Vector<?> getV() {
            return v;
        }

    }

person Alexander Mills    schedule 20.03.2014    source источник
comment
Vector для во всех смыслах и целях устарел, не используйте его. Его использование считается плохой практикой. Пример: использование Vector для ответа на вопрос на доске во время собеседования — отличный способ немедленно потерпеть неудачу. Кроме того, наивный подход к синхронизации в основном бесполезен в реальном мире, как и обертки Collections.syncronizedXXX.   -  person    schedule 20.03.2014


Ответы (3)


Они не эквивалентны. Вам нужен Collections.synchronizedList, который может "обернуть" любой список, включая ArrayList.

person Stuart Caie    schedule 20.03.2014

Краткий ответ: нет, это не эквивалентно.

Когда вы используете synchronized вокруг этого return ao;, ArrayList синхронизируется только во время инструкции возврата. Это означает, что 2 потока не могут получить объект одновременно, но как только они его получат, они смогут изменить его одновременно.

Если 2 потока выполняют этот код, add() не является потокобезопасным:

ArrayList<?> list = getAo(); // cannot be executed concurrently
list.add(something); // CAN be executed concurrently

Примечание: не используйте векторы, взгляните на этот пост, чтобы узнать, почему.

person Joffrey    schedule 20.03.2014

чтобы сделать эквивалент Vector, вы должны защитить любой доступ к любому элементу в коллекции, метод getAo просто синхронизирует доступ к списку массивов.

Если два потока вызывают getAo и после того, как каждый поток вызывает метод «добавить» для этого списка массивов, у вас может возникнуть проблема с несколькими потоками (поскольку «добавить» не синхронизируется).

Я рекомендую вам проверить атомарные классы, такие как CopyOnWriteArrayList: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArrayList.html

person Carlos Verdes    schedule 20.03.2014