5

我正在阅读 JVM 规范,试图弄清楚如何正确处理监视器。他们在相关部分给出的示例如下所示:

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

我无法弄清楚为什么需要第二个异常表条目。如果抛出异常,monitorexit我真的想再次尝试退出监视器吗?据我所知,可能抛出的异常是NullPointerExceptionand IllegalMonitorStateException

4

2 回答 2

4

有一个 Java 错误已作为“不是问题”关闭 - http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4414101。(感谢汤姆安德森找到它。)

Bug 的评估部分真的很有启发性。

它首先讨论处理“异步”异常;即ThreadDeath(已弃用!)Thread.stop()方法是如何实现的例外。神秘的处理程序确保即使“线程停止”发生在 JVM 试图释放锁的临界点,监视器锁也会被释放。

然后 Neil Gafter 补充说,根据 JLS,即使是假设的无限循环(如本问题中所述)也是正确的行为。JLS 表示监视器将始终在线程继续之前被释放。如果不可能做到这一点,那么将线程放入无限循环比做任何其他事情都更正确。

于 2013-08-15T13:43:05.260 回答
0

要清楚

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

我同意在第二个块上进行 try/catch 会令人困惑,因为这似乎是一个可能的无限循环。即如果在 13 和 16 之间发生异常,它会跳转到 13 来处理它。我只能假设

  • 有一个安全的、可重试的异常,它试图保护自己免受攻击。
  • 出于模糊的向后兼容性原因,它被保留。
  • 这没有充分的理由,它是字节码生成方式的产物。

我怀疑它没有做任何有用的事情,我想甲骨文的某个人也有同样的怀疑,但不确定它是否可以被删除。;)

于 2013-08-15T09:41:22.757 回答