views:

264

answers:

5
+3  Q: 

Reentrant locking.

A bit of help please, consider the bit of code below.

public class Widget {
    public synchronized void doSomething() {
        ...
    }
}

public class LoggingWidget extends Widget {
    public synchronized void doSomething() {
        System.out.println(toString() + ": calling doSomething");
        super.doSomething();
    }
}

I read that when doSomething() in LoggingWidget is called, the JVM will try to acquire a lock on LoggingWidget first and then on Widget.

I am curious to know the reason. Is it because the JVM knows that doSomething() has a call to super.doSomething() or because calling a subclass method will always acquire a lock on the superclass as well.

Cheers

+7  A: 

You are mistaken - the locks are obtained at the instance level. There is only one lock in your example because there is only one instance created when you say:

Widget w = new LoggingWidget

You can view locks (also known as monitors, mutexes or semaphores) as being individually "attached" to every object instance in the JVM.

If you had another synchronized method on the LoggingWidget subclass, you would see this to be true. It would not be possible to call this (new) method and the doSomething method at the same time.

This also holds true for another synchronized method on the superclass (i.e. it is not affected in any way by methods being overridden).

oxbow_lakes
A: 

There is only one instance to get the lock on, the instance of LoggingWidget, there is never an actual instance of Widget.

The lock is obtained when you call LoggingWidget.doSomething() and as you already have the lock when you call super.doSomething() that method is executed as normal.

Nick Holt
Thanks Nick, makes sense.
CaptainHastings
+4  A: 
public synchronized void doSomething() {
    System.out.println(toString() + ": calling doSomething");
    super.doSomething();
}

is the same as:

public void doSomething() {
    synchronized (this) {
        System.out.println(toString() + ": calling doSomething");
        super.doSomething();
    }
}

You're locking on the instance, not the class. So when super.doSomething() is called, you already have that instance locked.

bajafresh4life
Thanks, as the song goes, I can see clearly now ...
CaptainHastings
A: 

Reentrancy works by first acquiring the lock. When one thread acquires the lock it is known in the jvm. When entering a block of code that is synchronized with the thread that is currently holding a lock, they are allowed to continue through without re acquiring the lock. The jvm then increases a counter every reentrant action, further decreasing when exiting that block until the count is zero. When the count is zero the lock is released.

A: 

B.Goetz - "JJava Concurrency in Practice" if intrinsic locks were not reentrant, the call to super.doSomething would never be able to acquire the lock because it would be considered already held, and the thread would permanently stall waiting for a lock it can never acquire. Reentrancy saves us from deadlock in situations like this.

Loop