Синхронизация в 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