Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reentrant lock - Java concurrency in practice

Here is some sample code for reentrant locking from 'Java concurrency in practice':

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


}

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

The book explains that in the above code... "Because the doSomething methods in Widget and LoggingWidget are both synchronized, each tries to acquire the lock on the Widget before proceeding."

I ran the above code to observe the intrinsic lock. The above quote seems to imply that a thread acquires an intrinsic lock on the Widget object, but what I observed was that the thread acquires a lock on LoggingWidget. I am not sure how to verify the acquisition count, so wasn't able to observe that.

Is the book using the names LoggingWidget/Widget interchangeably or should I be observing a lock on the Widget object specifically?

Edit: Full Excerpt

Reentrancy facilitates encapsulation of locking behavior, and thus simplifies the development of object-oriented concurrent code. Without reentrant locks, the very natural-looking code in Listing 2.7 , in which a subclass overrides a synchronized method and then calls the superclass method, would deadlock. Because the doSomething methods in Widget and LoggingWidget are both synchronized, each tries to acquire the lock on the Widget before proceeding. But 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.

like image 240
sotn Avatar asked Jan 12 '15 10:01

sotn


People also ask

How does ReentrantLock work in Java?

A ReentrantLock is owned by the thread last successfully locking, but not yet unlocking it. A thread invoking lock will return, successfully acquiring the lock, when the lock is not owned by another thread. The method will return immediately if the current thread already owns the lock.

What is valid about synchronized and util concurrent locks ReentrantLock in thread concurrency in Java?

In case of a synchronized keyword, a thread can be blocked waiting for a lock, for an indefinite period of time and there was no way to control that. ReentrantLock provides a method called lockInterruptibly(), which can be used to interrupt thread when it is waiting for lock.

Why is ReentrantLock needed?

A ReentrantLock is owned by the thread last successfully locking, but not yet unlocking it. A thread invoking lock will return, successfully acquiring the lock, when the lock is not owned by another thread. The method will return immediately if the current thread already owns the lock.

Are Java locks fair?

You can specify the fairness of a lock when creating the ReentrantLock class. In a fair lock, threads acquire the lock in the order they request it. In a non-fair lock, jumping ahead is allowed. When requesting the same lock later, a later thread can get the lock before the waiting threads.


1 Answers

I'd need to see the excerpt to give you a specific answer. You can instantiate those classes in different ways. The lock is held on the object, so what the reference is does not matter. To illustrate that...

This class structure closely mimics yours.

public class GenericTest {
    public static void main(String... args) {
        Sub sub = new Sub();
        sub.go();
    }

    public synchronized void go() {
        System.out.println("Parent");
    }
}

class Sub extends GenericTest {
    @Override
    public synchronized void go() {
        System.out.println("Child");
        super.go();
    }
}

Run this program and stop executing further lines after acquiring a lock with a method of your pleasing (say System.in.read()). Find the pid of the java program and open it in Jconsole. Move to the threads section and highlight it every time the lock was acquired. You'll see the following traces.

my.package.common.GenericTest.go(GenericTest.java:30)
   - locked my.package.common.Sub@4c767286
my.package.common.Sub.go(GenericTest.java:42)
   - locked my.package.common.Sub@4c767286

Since this method is a member variable, the lock is on the current object (this) that executed the method in question. Notice how both locks are on Sub@4c767286.

[EDIT]

Edited my answer to suit your specific case.

like image 171
Deepak Bala Avatar answered Oct 11 '22 11:10

Deepak Bala