Синхронизация в Java - Vector против ArrayList

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

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;
        }

    }

3 ответа

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам