Вопрос

I was reading the JVM specification to try to figure out how to properly handle monitors. The example they give in the relevant section looks like this:

0   aload_1             // Push f
1   dup                 // Duplicate it on the stack
2   astore_2            // Store duplicate in local variable 2
3   monitorenter        // Enter the monitor associated with f
4   aload_0             // Holding the monitor, pass this and...
5   invokevirtual #5    // ...call Example.doSomething()V
8   aload_2             // Push local variable 2 (f)
9   monitorexit         // Exit the monitor associated with f
10  goto 18             // Complete the method normally
13  astore_3            // In case of any throw, end up here
14  aload_2             // Push local variable 2 (f)
15  monitorexit         // Be sure to exit the monitor!
16  aload_3             // Push thrown value...
17  athrow              // ...and rethrow value to the invoker
18  return              // Return in the normal case
Exception table:
From    To      Target      Type
4       10      13          any
13      16      13          any

I can not figure out why the second exception table entry is needed. If an exception is thrown by monitorexit do I really want to attempt to exit the monitor again? Possible exceptions thrown as far as I can tell are NullPointerException and IllegalMonitorStateException.

Это было полезно?

Решение

There is an Java Bug for this that has been closed as "Not an issue" - http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4414101. (Kudos to Tom Anderson for finding it.)

The Evaluation section of the Bug is really enlightening.

It starts by talking about dealing with "asynchronous" exceptions; i.e. the ThreadDeath exception that is how the (deprecated!) Thread.stop() method is implemented. The mysterious handler ensures that the monitor lock is released even if the "thread stop" happens at the critical point where the JVM is trying to release the lock.

Then Neil Gafter adds that even the hypothetical infinite loop (as described in this Question) is correct behaviour according to the JLS. The JLS says that monitor will always be released before the thread continues. If it is impossible to do that, then putting the thread into an infinite loop is more correct than doing anything else.

Другие советы

To be clear

block 0 :  0 -  3
block 1 :  4 - 10
block 2 : 13 - 16/17
block 3 : 18 

I agree that it it confusing to have a try/catch on the second block because this appears to be a possible infinite loop. i.e. if an exception occurs between 13 and 16 it jumps to 13 to handle it. I can only assume either

  • there is a safe, retry-able exception which it is try to protect itself from.
  • it is retained for an obscure backward compatibility reason.
  • there is no good reason for this and it is an artefact of how the byte code is generated.

I suspect it doesn't do anything useful, and I imagine someone at Oracle has had the same suspicious but didn't know for sure it could be removed. ;)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top