Stefan Falk
Stefan Falk

Reputation: 25387

Intrinsic Locks and Synchronization

I am currently reading about Intrinsic Locks and Synchronization on oracle.com where I came to this particular example:

Synchronized statements are also useful for improving concurrency with fine-grained synchronization. Suppose, for example, class MsLunch has two instance fields, c1 and c2, that are never used together. All updates of these fields must be synchronized, but there's no reason to prevent an update of c1 from being interleaved with an update of c2 — and doing so reduces concurrency by creating unnecessary blocking. Instead of using synchronized methods or otherwise using the lock associated with this, we create two objects solely to provide locks.

public class MsLunch {
    private long c1 = 0;
    private long c2 = 0;
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void inc1() {
        synchronized(lock1) {
            c1++;
        }
    }

    public void inc2() {
        synchronized(lock2) {
            c2++;
        }
    }
}

Before this section, synchronized methods where explained:

public synchronized void increment() {
    this.c++;
}

Which should be, and please correct me if I'm wrong, the same as

public void increment() {
    synchronized(this) {
        c++;
    }
}

if I do not add functionality to increment(), is that correct?

My question now comes from the phrase:

but there's no reason to prevent an update of c1 from being interleaved with an update of c2

I am not sure if I fully understand what "interleaved" means in this context. Does it mean, that if I e.g. remove lock2 from the MsLunch example:

public class MsLunch {
    private long c1 = 0;
    private long c2 = 0;
    private Object lock1 = new Object();
    // private Object lock2 = new Object(); // 'lock2' is no more!

    public void inc1() {
        synchronized(lock1) {
            c1++;
        }
    }

    public void inc2() {
        synchronized(lock1) { // Using 'lock1' here too
            c2++;
        }
    }
}

I could get in trouble with locking? Say thread-1 runs into inc1(), gets the lock from lock1 but gets suspended before being able to increment or release the lock. Now thread-2 is entering inc2() where another lock is created for lock1. Is this what is being avoided by using another lock2 and is this the reason why I would not use simply this as lock-provider? Or in other words: Can this cause a problem?

Upvotes: 1

Views: 429

Answers (1)

Vlad Bochenin
Vlad Bochenin

Reputation: 3072

Two locks here just to have possibility to increase c1 andc2 independently and not wait when the lock is released. So if Thread-1 enters to sync block inc1 and acquires a lock1, another Thread-2 will able increase c2 without waiting when thread-1 releases a lock.


Important to note:

Using of this as share monitor has an own issue because a reference on the instance of MsLunch is visible outside of MsLunch. For example. Thread-3 able to acquire a lock for: synchronized (msLunchInstance) outside of this class.

Upvotes: 4

Related Questions