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: By the inescapable power of Murphy's Law. "If anything can go wrong, it will." :-)
Which thread: According to Finagle's Law, it will be the one that causes the most damage. :-)
These so-called "laws" have not been demonstrated scientifically. But that doesn't mean you should ignore what they are intended to teach.