Понимание поведения Synchronized - PullRequest
2 голосов
/ 13 декабря 2011

Я пытаюсь лучше понять объем блокировки, выданной во время вызова synchronized.

Например:

class CopyOnReadList<T> {

    private final List<T> items = new ArrayList<T>();

    public void add(T item) {
        items.add(item);
    }

    public List<T> makeSnapshot() {
        List<T> copy = new ArrayList<T>();
        synchronized (items) {
            // Make a copy while holding the lock.
            for (T t : items) copy.add(t);
        }
        return copy;
    }

}

(Код с любовью заимствован у этот отличный ответ )

В этом фрагменте кода один поток может вызывать add, в то время как другой вызывает makeSnapshot ?. То есть, влияет ли блокировка, созданная synchronized (items) на все попытки чтения на items, или только на попытки с помощью метода makeSnapshot()?

Оригинальный пост фактически использовал блокировку synchonized в методе add:

public void add(T item) {
    synchronized (items) {
        // Add item while holding the lock.
        items.add(item);
    }
}

Каков побочный эффект удаления этого?

Ответы [ 3 ]

2 голосов
/ 13 декабря 2011

Влияет только на попытки в makeSnapshot () или, в более общем смысле, на любой другой метод, имеющий синхронизированный блок (items) (это означает, что он попытается установить блокировку на объекте items и заблокировать его, пока это не станет возможным).

Побочным эффектом удаления синхронизированного блока из метода add () является то, что add () не будет пытаться синхронизироваться с объектом items и, следовательно, разрешит одновременные изменения, в том числе во время выполнения makeSnapshot ().

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

1 голос
/ 13 декабря 2011

может ли один поток вызвать добавление, в то время как другой вызывает makeSnapshot?

Да.synchronized гарантирует, что любой другой поток не сможет ввести другой блок кода, который также синхронизирован, на том же объекте (в данном случае CopyOnReadList).Поскольку вы не синхронизировали метод add, несколько потоков могут одновременно вызывать add, даже если один поток выполняет makeSnapshot.

Удалив синхронизированный метод add, вы сделали код не потокобезопасным, поскольку ArrayList не является поточно-ориентированным.

Основное правило: каждый доступ (чтение или запись) в общее изменяемое состояние должны быть синхронизированы с той же блокировкой.

1 голос
/ 13 декабря 2011

В этом фрагменте кода один поток может вызвать добавление, в то время как другой вызывает makeSnapshot?

Конечно - и любой из методов может затем завершиться с ошибкой ConcurrentModificationException, илисодержимое списка может быть повреждено.

Влияет ли блокировка, созданная синхронизированными (элементы), на все попытки чтения элементов или только на попытки, сделанные с помощью метода makeSnapshot ()?

Ни.Блокировка никак не влияет на поведение объекта items, только на блоки или методы, которые синхронизируют его, а именно, чтобы гарантировать, что никакие два потока не могут выполнять ни один из этих блоков или методов одновременно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...