分散式物件特有的同步議題不多,但有一個根本問題值得注意:實作細節藏在介面之後。
- 行程呼叫一個(遠端)物件時,無從得知這個呼叫是否會連帶呼叫其他物件。
- 若物件受並行存取保護,可能形成一串呼叫端毫不知情的連鎖鎖定(cascading locks)。
- 對照之下,操作檔案或資料庫表這類受鎖保護的資料資源時,控制流程的樣貌對行程是可見的,行程在出狀況時能於執行期做更多處置(例如懷疑死結時主動放棄鎖)。交易處理系統普遍遵循這種可見模式。

圖 10-14:鎖定物件時的控制流程差異:(a) 物件式系統;(b) 以資料資源為中心的系統
因此在物件式分散式系統中,同步發生在哪裡、何時發生是必須弄清楚的問題。
同步位置的選項與代價:
- 物件伺服器端:同一物件的多個呼叫請求到達時,由伺服器序列化(伺服器自己要向外呼叫時也可能持有鎖)。缺點是呼叫端崩潰時,伺服器維護的鎖會把事情複雜化。
- 用戶端:Java 採此路線,但也有自己的缺點(見下)。
以 Java 的 synchronized 方法為例:
- 兩個行程同時呼叫 synchronized 方法時,只有一個能前進,另一個被擋下,藉此完全序列化對物件內部資料的存取;行程也可能在物件內部等待某條件成立而被擋下。
- 若要讓遠端物件的存取看起來與本地物件完全一致,就得在用戶端 stub(proxy)中擋下呼叫端;而另一台機器上的用戶端也得先在本地被擋下——這等於要跨機器同步多個用戶端,分散式同步相當複雜。
- 改為只在伺服器端擋原則上可行,但用戶端在呼叫處理期間崩潰時,需要頗為精密的協定來收拾,可能顯著拖累 RMI 的整體效能。
Java RMI 的設計者最後選擇:遠端物件的鎖定只限於 proxy 層。
- 效果:同一行程內的多條執行緒無法並行存取同一遠端物件;不同行程的執行緒則不受約束。
這種同步語意很弔詭:讀原始碼時看到的是乾淨漂亮的設計,實際執行分散式應用時卻可能冒出設計期就該處理的意外行為。這是一個清楚的例子,說明一味追求分佈透明性並不可取。