[英]Can a Synchronized Block be simplified to a Try-Finally Block on the Bytecode Level?
編寫我自己的編譯器用於類似Java的語言,我在編譯synchronized blocks
時遇到問題。 我想出了以下想法,將它們簡化為try-finally
塊:
synchonized (obj) {
statements...
}
可以替換
Object _lock = obj
_monitorEnter(lock)
try {
statements...
}
finally {
_monitorExit(lock)
}
凡_monitorEnter
和_monitorExit
代表MONITORENTER
和MONITOREXIT
說明。
我是否正確地假設如何編譯synchronized
,或者我錯過了什么?
編輯
我的實現以前對body中的return
和throw
語句有一些特殊處理。 基本上,它會在每個*RETURN
或THROW
指令之前手動加載所有lock
變量和MONITOREXIT
。 這是由finally
塊處理的,還是我還需要這些檢查?
你的假設是正確的。 Java語言中的synchronized
塊使用monitorenter
和monitorexit
指令實現。 您可以在此處查看JVM規范詳細信息。
Java虛擬機中的同步由監視器進入和退出實現,顯式地(通過使用monitorenter和monitorexit指令)或隱式地(通過方法調用和返回指令)。
編譯器生成的字節碼將處理synchronized
體內拋出的所有異常,因此您的try-finally方法在這里工作正常。
finally
語句的規范沒有說明釋放監視器的任何信息。 第一個鏈接中提供的示例顯示了包含在synchronized
塊中的簡單方法的字節碼。 如您所見,處理任何可能的異常以確保monitorexit指令執行。 您應該在編譯器中實現相同的行為(編寫將在finally語句中釋放monitor的代碼)。
void onlyMe(Foo f) {
synchronized(f) {
doSomething();
}
}
Method void onlyMe(Foo)
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
正如您所猜測的那樣,Java編譯器將同步塊編譯為類似於try-finally的內容。 但是,有一個小的區別 - 異常處理捕獲monitorexit
拋出的異常並且無限地嘗試釋放鎖。 在Java中沒有辦法像這樣指定控制流。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.