6

According to my understanding, the following piece of code should result in a deadlock. The reason being, when thread t1 locks static object firstData, he has acquired a lock on the class. So, when he tries to lock another static object secondData, the request should block.

However, the program runs fine and prints *** Successfully acquired both the locks

What is it about locking static objects that im missing here?

public class Deadlock {
    public static void main(String[] args) {

        Thread t1 = new Thread(new DeadlockRunnable());
        t1.start();
    }
} 

 class DeadlockRunnable implements Runnable {
    static  Object firstData = new Object();
    static  Object secondData = new Object();

    public void run() {
        synchronized(firstData) {
            synchronized(secondData) {
                System.out.println("*** Successfully acquired both the locks");
            }
        }
    }

}

For all those who answered that the locks are on object, instead of class, please take a look at this

Community
  • 1
  • 1
Chander Shivdasani
  • 9,878
  • 20
  • 76
  • 107

2 Answers2

14

Firstly, you have a mistake here:

The reason being, when thread t1 locks static object firstData, he has acquired a lock on the class.

Locking a static object locks only that object, not the class. You are locking two separate objects.

The question you refered to is about synchronized methods not synchronized statements. These two related constructs work in slightly different ways.


Secondly, even if you were locking on the same object, your code would still not deadlock (ideone). Intrinsic locks are reentrant. This means that a thread does not deadlock itself if it tries to take the same lock twice.

Reentrant Synchronization

Recall that a thread cannot acquire a lock owned by another thread. But a thread can acquire a lock that it already owns. Allowing a thread to acquire the same lock more than once enables reentrant synchronization. This describes a situation where synchronized code, directly or indirectly, invokes a method that also contains synchronized code, and both sets of code use the same lock. Without reentrant synchronization, synchronized code would have to take many additional precautions to avoid having a thread cause itself to block.

Source

Community
  • 1
  • 1
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • The following link made me believe so: http://stackoverflow.com/questions/437620/java-synchronized-methods-lock-on-object-or-class – Chander Shivdasani Apr 19 '12 at 22:33
  • I agree with @KirkWoll. But I have a question. So does that mean one thread can lock multiple static objects at the same time? – noMAD Apr 19 '12 at 22:33
  • 1
    @KirkWoll that is only true for reentrant locks – John Vint Apr 19 '12 at 22:33
  • @John, are you suggesting that you *can* produce a deadlock using a single thread in some situations? Please elaborate. – Kirk Woll Apr 19 '12 at 22:34
  • @Kirk Woll If we assumed that `synchronized` did not allow the owning thread to re-aquire it (ie reentrant) and the thread tried to acquire the same lock, an `isLocked` type method will return true in which the thread would be suspended. – John Vint Apr 19 '12 at 22:37
  • @John, so you are saying, "assume Java's synchronized keyword did not behave as it does..."? I'm confused how this digression applies to this question (or my comment). – Kirk Woll Apr 19 '12 at 22:38
  • I was just stating that for the sake of the argument. But if locks in Java were not reentrant one thread acquiring the same lock twice would result in a deadlock, ie that thread is waiting for itself to release the lock. – John Vint Apr 19 '12 at 22:40
  • @All: I was wondering why would you require nested `synchronized` methods for the same thread? What is the purpose of it since its the same lock? – noMAD Apr 19 '12 at 22:41
  • @noMAD The Vector class (or Collections.synchronizedList) is synchronized in every method. So imagine if the `addAll` method called `add` for each Object passed in as a parameter, it is acquiring the same lock twice but is required in both to ensure mutual exclusion for all actions to the Vector. – John Vint Apr 19 '12 at 22:43
  • @JohnVint: Well, this is a good case for the nested `synchronized`. But say hypothetically, `vector` was not `synchronized` and we had to do it explicitly. Wouldn't it be enough just to synchronize `addAll()` and let `add()` be alone even though `addAll()` calls `add()`?? – noMAD Apr 19 '12 at 22:52
  • 1
    @noMAD that is absolutely correct to assume. It actualy has a name. Its called lock coarsening. That optimization is built into Java's JIT. – John Vint Apr 19 '12 at 23:42
1

"when thread t1 locks static object firstData, he has acquired a lock on the class"
Not sure why you think so. t1 acquires a lock on firstData, not on the containing class. There is no possible deadlock in your code as it is.

EDIT
Following your comment, the link is about the difference between those 2 declarations:

public synchronized method() // lock on the instance (this)
public static synchronized method() // lock on the class (Myclass.class)

But there is no link with deadlocks.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • The following link made me believe so http://stackoverflow.com/questions/437620/java-synchronized-methods-lock-on-object-or-class – Chander Shivdasani Apr 19 '12 at 22:33
  • @assylias : Could you please explain what object gets locked when t1 acquires lock on 'firstData' (static field)... did you mean only the Object firstData gets locked? ... Neither the class nor the container DeadlockRunnable object ? – Twaha Mehmood Dec 08 '14 at 09:49
  • @tm.sauron Yes - a lock is tied to a specific object, in this case `firstData` and `secondData` - the enclosing class `DeadlockRunnable` plays no other role than a code container here... – assylias Dec 08 '14 at 10:08