问题
I'm new to Java and OOP. I'm reading concurrency in java and in chapter 2, it talks about re-entrancy. I don't quite understand how a deadlock situation would occur. Can some one break this situation down for me to understand the details line by line?
Thank you in advance.
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.
public class Widget {
public synchronized void doSomething() {
...
}
}
public class LoggingWidget extends Widget {
public synchronized void doSomething() {
System.out.println(toString() + ": calling doSomething");
super.doSomething();
}
}
and the thread would permanently stall waiting for a lock it can never acquire.
How, why, which thread?
回答1:
How, why, which thread?
The thread that deadlocks is the thread that attempts to acquire the lock; i.e. this one.
How:
Obtain reference to a
LoggingWidget
instanceCall
doSomething()
on the instanceThe call to
LoggingWidget.doSomething()
acquires the lock on the instance, since the method issynchronized
.The called method then calls
super.doSomething()
.The call to
Widget.doSomething()
tries to acquire the lock on the instance (again!), since the supertype method is alsosynchronized
.
At step #5. the current thread attempts to acquire a primitive lock on an instance that it has already locked. If primitive locks were not reentrant, then that would deadlock ...
"some thread" already holds the lock on the object, so we have to wait for that thread to release the lock,
that "some thread" is the current thread ... and we are not going to release the lock until we return from the
LoggingWidget.doSomething()
but that can't happen until after we've completed the call to
Widget.doSomething()
and that can't happen until after we've acquired the lock
..... DEADLOCK!
But fortunately, there is no deadlock in reality. The fact that primitive locks are reentrant means that step #5 doesn't need to acquire the lock (it already has it), and the whole waiting-for-myself-to-do-something-that-cannot-happen scenario simply does not arise.
Why: The inescapable power of causality :-)
回答2:
I think you got confused by the author's use of the word re-entrancy. By "locks are re-entrant" he meant that if your thread holds a lock already, Java allows entering a synchronized
method from inside another synchronized
method, or re-entering the same synchronized
method recursively.
This is different from a more common meaning of re-entrancy as the ability of a piece of code to be re-entered, concurrently or on the same thread when the status is preserved.
Without re-entrancy in the author's meaning the synchronized
of the super.doSomething()
would block on trying to acquire the lock held by this.doSomething()
, because they block on the same object (namely, on this
).
回答3:
You have two methods that lock on the same object - an instance of LoggingWidget
- that would be run by the same thread.
- An instance of
LoggingWidget
is created - The
doSomething
method defined in theLoggingWidget
class is called against that instance - A lock on the instance of
LoggingWidget
is obtained - The
println
statement is executed - The
doSomething
method of theLoggingWidget
class calls thedoSomething
method defined in theWidget
class - A lock on the same instance of
LoggingWidget
is needed to proceed, but it's already held by the thread executing the first method
If locks were not re-entrant, a deadlock would occur at step 6 since the lock on the instance is already held. But since built-in Object
locks in Java are re-entrant, step 6 continues as normal since the lock that is needed is already held by the executing thread.
来源:https://stackoverflow.com/questions/21518938/re-entrancy-in-java-saves-us-from-a-deadlock-situation-in-this-code-sample-how