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

5

56

I know the difference between synchronized method and synchronized block but I am not sure about the synchronized block part.

Assuming I have this code

class Test {
  private int x=0;
  private Object lockObject = new Object();

  public void incBlock() {
    synchronized(lockObject) {
      x++;
    }
    System.out.println("x="+x);
  }

  public void incThis() {  // same as synchronized method
    synchronized(this) {
      x++;
    }
    System.out.println("x="+x);
  }
}

In this case what is the difference between using lockObject and using this as the lock? It seems to be the same to me..

When you decide to use synchronized block, how do you decide which object to be the lock?

Awn answered 30/7, 2010 at 7:0 Comment(5)
I found the answer to my question in #3048064 If you look at the answer, it's very clear that if there are 2 threads (t1 and t2) where t1 calls x.addA() and t2 calls x.addB(). If both addA and addB use this as the lock, then x.addA() and x.addB() can't run concurrently. Whereas if if addA and addB uses different object for the lock, both method can run concurrentlyAwn
Just to check something: In the example above, when you use lockObject to effectively guard access to x is there not a situation where another thread could get in after the synchronised block but before the println and increase x again? I.e. do you really need the println within the synchronised block?Giuditta
ah true, i should've put it in the synchronised block, but i've already answered my own question :DAwn
@Awn Let me get this clear. Using a private object as a lock guarantees you that threads that use the same instance of your Test class will get synchronized, if they try to access the method at the same time. If there is more than one instance of the Test class, lock objects will be different. i.e. threads that that use separate instances will not get synchronized (unless more than one uses the same instance). Is this correct?Ramayana
@user1107412 yes, that's correct. The reason why using private object is preferable is that other object can't use the same lock (unlike using this)Awn
E
74

Personally I almost never lock on "this". I usually lock on a privately held reference which I know that no other code is going to lock on. If you lock on "this" then any other code which knows about your object might choose to lock on it. While it's unlikely to happen, it certainly could do - and could cause deadlocks, or just excessive locking.

There's nothing particularly magical about what you lock on - you can think of it as a token, effectively. Anyone locking with the same token will be trying to acquire the same lock. Unless you want other code to be able to acquire the same lock, use a private variable. I'd also encourage you to make the variable final - I can't remember a situation where I've ever wanted to change a lock variable over the lifetime of an object.

Emeldaemelen answered 30/7, 2010 at 7:4 Comment(5)
can you elaborate more? Say class A having instance of Class B. Now B has some member variable. When A calls any method of B, it gets lock on this/instance member...right? Means gets lock on instance of B itself or its member... can u just explain the difference?Boulogne
@Paarth: Your comment isn't clear - do you mean should B lock on the private lock for every method? That depends on the purpose of the class itself. Most classes don't need to try to be thread-safe at all, to be honest.Emeldaemelen
yah, so i it needs to make sync method, it shuold use private member object instead of 'this' ... right? ok...Boulogne
synchronised(new Object ) vs synchronised(this ) what is the actual difference between this two, when to use which oneHenning
@MaheshwarLigade: You should never create a new object just for a single synchronized block like that - there'd be no other code that could synchronize against the same object. You'd normally create a final variable within the class, e.g. private final Object lock = new Object(); and synchronize against that instead. That's better than synchronizing against this as you know that only your code has access to that monitor to synchronize on it.Emeldaemelen
F
14

I had this same question when I was reading Java Concurrency In Practice, and I thought I'd add some added perspective on the answers provided by Jon Skeet and spullara.

Here's some example code which will block even the "quick" setValue(int)/getValue() methods while the doStuff(ValueHolder) method executes.

public class ValueHolder {
    private int value = 0;

    public synchronized void setValue(int v) {
        // Or could use a sychronized(this) block...
        this.value = 0;
    }

    public synchronized int getValue() {
        return this.value;
    }
}

public class MaliciousClass {

    public void doStuff(ValueHolder holder) {
        synchronized(holder) {
            // Do something "expensive" so setter/getter calls are blocked
        }
    }
}

The downside of using this for synchronization is other classes can synchronize on a reference to your class (not via this, of course). Malicious or unintentional use of the synchronized keyword while locking on your object's reference can cause your class to behave poorly under concurrent usage, as an external class can effectively block your this-synchronized methods and there is nothing you can do (in your class) to prohibit this at runtime. To avoid this potential pitfall, you would synchronize on a private final Object or use the Lock interface in java.util.concurrent.locks.

For this simple example, you could alternately use an AtomicInteger rather than synchronizing the setter/getter.

Faro answered 2/8, 2010 at 1:45 Comment(0)
A
6

Item 67 of Effective Java Second Edition is Avoid excessive synchronization, thus I would synchronize on a private lock object.

Arctic answered 30/7, 2010 at 7:7 Comment(1)
It does not answer the question (use synchronized or Locks), no real explanation, broken link (archived version). Downvoted.Filide
C
2

Every object in Java can act as a monitor. Choosing one is dependent on what granularity you want. Choosing 'this' has the advantage and disadvantage that other classes could also synchronize on the same monitor. My advice though is to avoid using the synchronize keyword directly and instead use constructs from the java.util.concurrency library which are higher level and have well defined semantics. This book has a lot of great advice in it from very notable experts:

Java Concurrency in Practice http://amzn.com/0321349601

Charry answered 30/7, 2010 at 7:9 Comment(0)
R
0

In this case it does not matter which object you choose for lock. But you must consistently use the same object for locking to achieve correct synchronization. Above code does not ensure proper synchronization as you once use the 'this' object as lock and next the 'lockObject' as lock.

Reconvert answered 30/7, 2010 at 7:5 Comment(2)
I understand that it's not a proper synchronization since it uses different lock for different method, I'm just trying to understand the difference between using 'this' and 'lockObject' for the lockAwn
oh.. sorry for misunderstanding your question. So for that, the answer would be same as what Jon Skeet has answered.Reconvert

© 2022 - 2024 — McMap. All rights reserved.