0

I think this question must have been asked somewhere but when I look for it I unfortunately find only different topics. Anyway here is the code:

public class A {
    Object lockX = new Object();
    Object lockY = new Object();
    Object lockZ = new Object();
    int c1;
    int c2;

    public void foo1() {
        synchronized(lockX) {
            c1++;
        }
    }

    public void bar1() {
        synchronized(lockY) {
            c1++;
        }
    }

    public void foo2() {
        synchronized(lockZ) {
            c2++;
        }
    }

    public void bar2() {
        synchronized(this) {
            c2++;
        }
    }
}

Basically foo1 and bar1 are incorrect. They use different lock to protect c1, so in fact c1 won't be protected and both those functions can run concurrently. My question however is about foo2 and bar2. Are they ok? They also use different locks but bar2 is locking whole object, so does it prevents modifing c2 concurrently?

user1723095
  • 1,181
  • 1
  • 13
  • 24
  • 1
    You have four different locks, `lockX`,`lockY`,`lockZ` and `this`. None of them will block any of the others. – khelwood Aug 05 '15 at 14:27
  • 2
    In a real program, you should use AtomicInteger instead if you simply want to count something from multiple threads. – Raphaël Aug 05 '15 at 14:28

4 Answers4

5

bar2 is locking whole object

Once you properly understand the semantics of mutual exclusion locks (mutexes), you will realize that this is an empty statement. A mutex doesn't have any inherent scope: a thread either does or does not hold it at any point in time. Synchronizing on this simply acquires the mutex associated with the this instance. Synchronizing on lockZ acquires an entirely independent mutex, and both can be acquired at the same time.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
1

foo2 and bar2 are similar to foo1 and bar1. In case of bar2 the lock is on class A object where as foo2 is using lock of object lockZ.

The object this doesn't become locked, rather the object this is used as the mutex and the body is prevented from executing concurrently with other code sections also synchronized on this.

TheCodingFrog
  • 3,406
  • 3
  • 21
  • 27
1

The quick answer is: NO. Even c2 is not protected for concurrent access because is locked by different object instances. Moreover a better form for

    public void bar2() {
        synchronized(this) {
            c2++;
        }
    }

is

    synchronized public void bar2() {
        c2++;
    }
Alepac
  • 1,833
  • 13
  • 24
0

As mentioned in @Marko's the semantics of locking is different from what you already conceive.

Synchronizing on an object X does not mean you are applying an access/method execution restriction on object X itself. When a certain thread A synchronizes over an instance X, it restricts other threads from synchronizing on the same instance X until the thread A finishes execution inside the synchronized(X) block and thus releasing the lock over object X. To make it more clear, only one thread at a time can acquire a lock on a single immutable instance of an object, and until this lock is released, any other thread that is trying to acquire a lock on the same instance will block.

Think of a synchronized block as a room with a door, and this door opens with a key, when a thread wants to enter the room and do stuff inside, it takes a key, opens the door then goes inside but keeping the key with it, other threads that want to enter the room with the same key have to wait on the door until the thread inside finishes its business, leaves the room and sets the key free for other threads to use it. If another thread uses a different key, while another thread is already in the room, it can enter the same room and do its business inside while the other thread is still in there and thus those two threads can modify the same stuff in the room, which may cause what is described as a race condition.

So in your case the answer is : No.

Community
  • 1
  • 1
sm_
  • 2,572
  • 2
  • 17
  • 34