1

In the sample code

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

on this page,

lock1 and lock2 are controlling the updates on c1 and c2 resply.

However,

    synchronized(lock2) 

is acquiring the lock of the object lock1 and releasing it when the synchronized block

    synchronized(lock1) {
        c1++;
    }

is executed.

While this block is being executed, there may be an update on member c1 of this object still-- and I don't see how this update is being prevented by synchronizing on lock1 as in the code.

It is the object lock1 that there is exclusive access on-- and nothing else(?)

So, how is the implementation

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

in the above code different from

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

or even

public void inc1() {
    synchronized(c1) {
        //do something on c1
    }
}

when c1 is an object but not a primitive?

What am I missing here ?

Note: I saw

What is the difference between synchronized on lockObject and using this as the lock?

and

Java synchronized method lock on object, or method?

among some other discussions.

Community
  • 1
  • 1
Roam
  • 4,831
  • 9
  • 43
  • 72

5 Answers5

7

Implementation 1.

You are locking on the lock1 object. Nothing else that needs a lock on lock1 can execute. Having your two methods lock on different objects means that the two methods can run concurrently, but no two threads can run the same method concurrently.

Implementation 2.

Making a method synchronized means that the entire method body is implicitly in a synchronized(this) block (or synchronized on the Class object if the method is static. If both methods are synchronized, then one method would prevent the other from running at the same time, which is different then locking both methods on different objects.

Implementation 3.

If c1 is an object and not a primitive, then the semantics are very similar to implementation 1 - locking on an explicit object.

rgettman
  • 176,041
  • 30
  • 275
  • 357
  • as far as i see, your first par. verifies what i'm saying. so, what's the point in that implementation? the lock of lock1 is acquired only and c1 is still in the "loose". how does "Implementation 1"-- the way you stated in your ans. differ from "Implementation 2"? – Roam Aug 09 '13 at 23:21
  • 1
    The difference comes in when you have multiple locks - Implementation 1 allows one thread to lock on `lock1`, but another thread is able to lock on `lock2`. It is also possible for two threads to deadlock here - if thread "A" owns `lock1` and thread "B" owns `lock2`, but then thread "A" wants to lock `lock2` and thread "B" wants to lock `lock1`. In implementation 2, there is only 1 lock, so a deadlock is not possible here. But a thread can't execute one `synchronized` method if the other `synchronized` method is being executed; the lock is being held. – rgettman Aug 09 '13 at 23:27
  • In this case, i can have another method public void decr1() { c1--; } in the same class. so in this case, decr1() can execute and update c1 while incr1 is being run by some other thread (?) since it's lock1 that is locked, not c1. ami not right? – Roam Aug 09 '13 at 23:34
  • If you were to add a `decr1` method operating on `c1`, then have it lock on `lock1` (the same lock object that `incr1` uses), so two threads can't be updating `c1` at the same time, with either method. – rgettman Aug 09 '13 at 23:37
  • thx for the useful answer. explains the intent of lock1/lock2. – Roam Aug 09 '13 at 23:43
0

Your statement is as far as I know incorrect. The page you linked doesn't state what you claim in your question neither. This is how locks work: Locks do not prevent threads of accessing an object at all. Locks only prevents another thread of acquiring the same lock while another thread already has acquired that lock.

This means that this can happen:

Thread A: synchronize (lockObject)
Thread B: lockObject.toString();
Thread A: release the lock on lockObject

This is what happens when two Threads want the same lock at the same time:

Thread A: synchronize (lockObject)
Thread B: synchronize (lockObject) // This will block until (1) !
Thread A: do some stuff and then release lock on lockObject
Thread B: gets the lock (1)

However:

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

is exactly the same as:

public void inc1() {
    synchronized(this) {
        c1++;
    }
}
Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
  • Correct, they are the same. This means that in a given object instance, all code that is synchronized (blocks or keywords on methods) lock on the same lock object. If that's not what you want/need, use different lock objects as arguments to synchronized blocks. – Tim Aug 09 '13 at 23:15
  • @Roam: The facts of what he wrote are correct, though the original phrasing left a bit to be desired. – Tim Aug 09 '13 at 23:16
  • 1
    My answer isn't bogus at all. I'm just telling you the truth. :) – Martijn Courteaux Aug 09 '13 at 23:23
  • I think I'll leave my answer as-is right now. So feel free to read :) I know, "a lie" was maybe a bad choice of word and was definitely not meant as a personal attack, but more as a general truth. – Martijn Courteaux Aug 09 '13 at 23:26
  • 1
    While reading your comments to other questions, I think you still do not fully understand the first part of what I wrote. Here is another attempt to clarify: Using synchronized blocks **only** affects behavior of other synchronized blocks (and really nothing else). That is the key to hold while programming multi-threaded applications. Synchronized code does not prevent other non-synchronized code of executing or accessing locked objects. – Martijn Courteaux Aug 09 '13 at 23:37
  • @Roam At First, Learn some basic manners to respect the volunteers., before learning the technical things. – Muthu Ganapathy Nathan Nov 15 '13 at 13:15
0

Marking a block or method synchronized without specifying a lock object synchronizes on the object who owns the method; in this case, the MsLunch instance. It's equivalent to synchronized(this). The purpose of the lock-object idiom is to break that lock up so that c1 and c2 can be manipulated separately. A synchronized block can only synchronize on an object, not a primitive.

chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152
0
synchronized(lock2){
  // do sth
}

is actually acquiring lock of object lock2

where as

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

acquires object on this object.

locks acquired by synchronized will be released once the program leaves the block.

bolei
  • 156
  • 5
  • 13
  • well, thats fine. so what's the point in the implementation on page http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html ? – Roam Aug 09 '13 at 23:23
0

I was having trouble with one thread hogging the lock

for(;;){synchronized(lockObject){
...
}}

I guess Java doesn't like to unlock it on its own the first chance it gets.

Using an java.util.concurrent.locks.ReentrantLock fixed the problem

static ReentrantLock lock = new ReentrantLock();
for(;;){
  lock.lock();
  ...
  lock.unlock();
}
sadjkas sadal
  • 51
  • 1
  • 1