4

Java can detect a deadlock that is about to happen (or at least in some cases)

For example, consider the following:

Thread A acquires Lock A
Thread B acquires Lock B
Thread A tries to acquire Lock B - and blocks
Thread B tries to acquire Lock A - and blocks indefinitely

In the last statement, the JVM knows that it will end up in a deadlock (because it knows which thread holds which lock).

So my question is, why the JVM doesn't throw a runtime error upon the lock acquisition that will cause a deadlock, resulting in termination of the thread (like any other unhandled exception), and releasing its locks, again, like normal.

For example, in a database, if a transaction tries to lock some record and the DB figures out it will be deadlocked, that transaction is aborted. The same can be applied to threads, so why not?

paranoidAndroid
  • 523
  • 5
  • 12
  • 1
    that's a good question, I presume the jvm designers are leaving the responsibility for handling the illegal state to a developer. the contract for those isn't meant to handle incorrect programming and consequences to the business logic outside of its scope. it might make a good non-default configuration option though in my opinion. – MarianP Jul 24 '20 at 21:53
  • @MarianP yes, but the same can be said about trying to call wait() for example while not holding the monitor. In which case - an IllegalMonitorStateException is thrown. Anyways, the deadlock results in two or more threads hanged and the developer cannot do anything with it once it reached this state. – paranoidAndroid Jul 24 '20 at 21:57
  • ok, maybe the problem is in defining a deadlock. it is probably only detected by an outside thread, not time deterministically. not something that clicks immediately when it happens – MarianP Jul 24 '20 at 21:59
  • Perhaps the issue is one of backwards compatibility: this wasn't done originally, and making it do so would violate the earlier language specifications. It is possible to detect them, using mechanisms such as those described here https://stackoverflow.com/q/1102359/3788176, so there must be a reason like backwards compatibility for *not* trying to detect them. – Andy Turner Jul 24 '20 at 22:02
  • @AndyTurner that's what I had in mind. But I don't see how it could break anything, backwards-compatible wise. Because, a deadlock is already breaking your program in this way or another, so having a exception thrown with details about the specific condition that caused the deadlock seems very helpful. It's not like someone was relying on a deadlock happening and now we break this assumption ;) – paranoidAndroid Jul 24 '20 at 22:05
  • JVM doesn't throw exception but it provides `Lock` with `tryLock()` that allow you to detect and manage deadlocks https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html – Ivan Jul 24 '20 at 22:11
  • 2
    Re, "the JVM knows..." There's a difference between having all of the facts available and _knowing_. The JVM can only _know_ that the last step will cause a deadlock if, every time any thread attempts to lock a lock, it first runs a graph-search algorithm on all of the locks and owners. For some applications, the performance penalty is too high, and the developers would rather _prove_ that deadlocks are impossible, or else fix the problem if they can't prove it. – Solomon Slow Jul 24 '20 at 22:12
  • @SolomonSlow that's a valid argument indeed. I would say that the JVM could run this graph search every once in a while, in background (for example, in a GC cycle) and then throw appropriate exceptions from the appropriate thread. But your point is totally valid. I haven't thought about it. – paranoidAndroid Jul 24 '20 at 22:14
  • good discussion about things I have thought about in the past. I would add my recent experience with a 3 thread deadlock, 1st was locking the 2nd, 2nd was locking the 3rd and 3rd was locking the 1st. I could see that in jvisualvm, but the guarantee that it is detected or how fast is not there. what if 100 threads were doing something funny like that. in the end the language/jvm designers leave that responsibility to a programmer or an operations person. there are 2 ways to prevent deadlocks, locking and unlocking in the same and reverse order. or timeouts. we have the timing out locks option. – MarianP Jul 24 '20 at 22:32
  • and I have seen code that was interrupting deadlocked threads. it was ugly, but perhaps not much worse than having this out of the box. – MarianP Jul 24 '20 at 22:33
  • @paranoidAndroid I would argue it's safer to remain in a deadlocked state (and do nothing) than it is to have a thread attempt to recover by catching an exception *if you were never expecting that to happen when you wrote that code*. Deadlocking is bad; concurrent code proceeding in an unanticipated way seems far worse. – Andy Turner Jul 24 '20 at 22:40
  • @AndyTurner I'm not saying the programmer should expect this exception and catch/handle it. Im saying that a runtime error can be thrown and the thread will abort, like it would abort in any other exception; like, the programmer doesn't expect NullPointerExceptions, but they still happen and terminate his thread – paranoidAndroid Jul 24 '20 at 22:43
  • @paranoidAndroid as an example: imagine `while (true) { try { synchronized (A) { giveAwayMoney(); synchronized (B) { } } (catch (RuntimeException e) {} }`: there are vastly different consequences of not throwing vs throwing if acquiring B would result in deadlock. It's not backwards compatible. – Andy Turner Jul 24 '20 at 22:44
  • 1
    It's not very useful to throw exceptions for problems that should have been sorted out during testing. Deadlock is easy to avoid within a single program. Where it gets hard and needs detection is in distributed systems like database servers. – user207421 Jul 25 '20 at 00:29

0 Answers0