Marty Pitt
Marty Pitt

Reputation: 29280

Understanding the behaviour of Synchronized

I'm trying to improve my understanding of the scope of the lock issued during a synchronized call.

Eg:

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

}

(Code lovingly borrowed from this excellent answer)

In this code snippet, can one thread call add while another is calling makeSnapshot?. Ie., does the lock created by synchronized (items) affect all attempted reads to items, or only those attempted through the makeSnapshot() method?

The original post actually used a synchonized lock in the add method:

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

What is the side effect of removing this?

Upvotes: 2

Views: 138

Answers (3)

soulcheck
soulcheck

Reputation: 36767

It affects only those attempted in makeSnapshot() or, more generally, any other method that has synchronized(items) block (it means that it will try to aquire lock on items object and block until it's possible).

The side effect of removing synchronized block from add() method is that add() will not try to synchronize on items object, and therefore will allow concurrent modifications, including while makeSnapshot() is executing.

Without synchronize in add() you can have other threads add elements to items collection WHILE the snapshot is being made.

Upvotes: 2

JB Nizet
JB Nizet

Reputation: 691685

can one thread call add while another is calling makeSnapshot?

Yes. synchronized makes sure that any other thread can't enter another block of code which is also synchronized, on the same object (the CopyOnReadList, in this case). Since you have not synchronized the add method, several threads can call add concurrently, even if one thread is executing makeSnapshot.

By removing the synchronized on the add method, you've made the code non-threadsafe, since ArrayList is not thread-safe.

The rule of thumb is: every access (read or write) to a shared mutable state must be synchronized on the same lock.

Upvotes: 1

Michael Borgwardt
Michael Borgwardt

Reputation: 346260

In this code snippet, can one thread call add while another is calling makeSnapshot?

Certainly - and either one of the methods can then fail with a ConcurrentModificationException, or the content of the list may be corrupted.

does the lock created by synchronized (items) affect all attempted reads to items, or only those attempted through the makeSnapshot() method?

Neither. The lock has not effect whatsoever on the behaviour of the object items, only on blocks or methods that snychronize on it - namely to ensure that no two threads can execute any of those blocks or methods at the same time.

Upvotes: 1

Related Questions