[英]Java RMI and synchronized methods
我正在研究“分布式系統”一書(由Tanenbaum和Van Steen撰寫),他們說的東西似乎與許多人在Java RMI和同步方法上的想法相沖突。
我認為在遠程對象實現上使用synchronized方法 (因此在服務器上運行的實際實現)即使對該方法的調用來自不同的客戶端機器(通過代理調用該方法),也會阻止該方法的並發執行......又名Stub)。
我已經看到很多人有相同的看法,例如在這里看看: Java RMI和線程同步問題
在本書中,它表示使用RMI時不會阻止同步方法的並發執行。
這是本書的相關摘錄(您只能閱讀粗體句子,但如果您願意,可以閱讀上下文):
邏輯上,遠程對象中的阻塞很簡單。 假設客戶端A調用遠程對象的同步方法。 要使對遠程對象的訪問看起來與本地對象完全相同,有必要在實現對象接口的客戶端存根中阻止A,並且A有直接訪問權限。 同樣,在將其請求發送到服務器之前,還需要在本地阻止另一台機器上的另一個客戶端。 結果是我們需要在不同的機器上同步不同的客戶端。 正如我們在Chap中討論的那樣。 6,分布式同步可能相當復雜。
另一種方法是僅允許在服務器上進行阻止。 原則上,這樣可以正常工作,但是當客戶端在服務器處理其調用時崩潰時會出現問題。 正如我們在Chap中討論的那樣。 8,我們可能需要相對復雜的協議來處理這種情況,這可能會顯着影響遠程方法調用的整體性能。
因此,Java RMI的設計者選擇僅限制代理對遠程對象的阻塞(Wollrath等,1996)。 這意味着將阻止同一進程中的線程同時訪問同一個遠程對象,但不同進程中的線程不會。 顯然,這些同步語義很棘手:在語法層面(即,在閱讀源代碼時),我們可能會看到一個漂亮,干凈的設計。 只有在實際執行分布式應用程序時,才能觀察到應該在設計時處理的意外行為。 [...]
我認為文章“Java系統的分布式對象模型”( 可在此處獲得 )在文本中引用了Wollrath et all, 1996
在括號之間。 然而,我在該論文中找到的唯一相關段落就是這一段:
由於本地和遠程對象的故障模式不同,分布式等待和通知要求所涉及的實體之間的協議更復雜(例如,客戶端崩潰不會導致遠程對象永久鎖定),因此,不能輕易地適應Java中的本地線程模型。 因此,客戶端可以在遠程引用上使用notify和wait方法,但該客戶端必須知道此類操作不涉及實際的遠程對象,只涉及遠程對象的本地代理(存根)。
我是以錯誤的方式解釋文本還是事實上說使用RMI時同步方法“不是那么同步”?
您的第一個參考是,在單個VM實例中,RMI Stub(客戶端到RMI服務器)上的調用將在內部同步。 也就是說,存根(或代理,如文本似乎稱之為)本身將阻止多個線程同時調用遠程服務器上的方法。 但是,它澄清了兩個具有遠程服務器存根的虛擬機不會被阻止同時調用遠程服務器(這很明顯,因為它們不能共享鎖,而且RMI本身不會阻止服務器的並發)。 如果這是不合需要的,則RMI服務器必須實現鎖定機制以防止多個並發調用。
第二個參考文獻並不反對第一個參考文獻。 第二個只是澄清,如果您嘗試在存根上進行同步,它將僅在本地鎖定,並且不會影響遠程服務器的並發性。
結合這兩個文本,我們可以看到在存根上進行同步將阻止同一VM中的多個線程同時訪問遠程,但不會阻止不同VM中的線程進行並發訪問。
據我所知,每次調用RMI服務器都會在服務器端創建一個新線程(由我的2000日志文件見證)。 如果在服務器端進行同步,則應該是安全的。 你發布的文章中我遇到了一些古老的警告。 作為一個實踐者,我更喜歡運行該軟件一個月左右,並認為它足夠穩定,可用於生產。 如果這並不令人滿意,我很抱歉。
您還應該知道Java多線程自1996年以來發生了重大變化。作為原始語言設計一部分的notify()和wait()方法從並發專家和Java 5中得到了很多抨擊(2004年,維基說引入了像ReentrantLock這樣的高級並發對象 ,這些對象現在是首選的做事方式。
所以你提到的批評可能是正確的,但已經過時了。
你是對的。 文字錯了。 RMI存根是線程安全的,可以由單個客戶端JVM中的多個線程同時調用。 我不知道Wollrath所說的任何聲明或文字都說不同,自1997年以來我就一直關注這個話題。
特別:
我認為在遠程對象實現上使用synchronized方法(因此在服務器上運行的實際實現)即使對該方法的調用來自不同的客戶端機器(通過代理調用該方法),也會阻止該方法的並發執行......又名Stub)。
你是對的。
在本書中,它表示使用RMI時不會阻止同步方法的並發執行。
這本書不僅錯誤,而且說不可能。 RMI究竟如何阻止同步工作?
邏輯上,遠程對象中的阻塞很簡單。 假設客戶端A調用遠程對象的同步方法。
然后通過Java的正常操作在服務器上發生阻塞。
要使對遠程對象的訪問看起來與本地對象完全相同,有必要在實現對象接口的客戶端存根中阻止A,並且A有直接訪問權限。
垃圾。 遠程方法實現synchronized
的事實做了所有必要的事情。
同樣,在將其請求發送到服務器之前,還需要在本地阻止另一台機器上的另一個客戶端。
這又是垃圾。
結果是我們需要在不同的機器上同步不同的客戶端。
再次垃圾。
另一種方法是僅允許在服務器上進行阻止。
'允許'? 這是什么意思? synchronized
方法是synchronized.
你不能不允許它。
原則上,這樣可以正常工作,但是當客戶端在服務器處理其調用時崩潰時會出現問題。
再次垃圾。 沒有出現這樣的問題。 服務器通過讀取超時或寫入異常甚至成功完成遠程方法從這種情況中恢復。 在所有三種情況下,方法退出,同步鎖定被釋放,生命繼續。
正如我們在Chap中討論的那樣。 8,我們可能需要相對復雜的協議來處理這種情況,這可能會顯着影響遠程方法調用的整體性能。
廢話。
因此,Java RMI的設計者選擇僅限制代理對遠程對象的阻塞(Wollrath等,1996)。
我不知道除了你所引用的摘錄之外還有什么可以引用的,而且我已多次讀過那篇論文。 如果作者想要依賴這篇論文,他們應該為章和節提供引文和適當的引用。
無論如何,RMI的設計者沒有做出這樣的選擇。 沒有這樣的選擇。 無論RMI設計者可能想要什么,也可能不想要synchronized
都是synchronized
的,類似的notify()
和wait()
也是final.
他們無法做出任何選擇。 您提供的引用不是“選擇”:它僅僅是關於Java語義的聲明。
我是以錯誤的方式解釋文本還是事實上說使用RMI時同步方法“不是那么同步”?
我認為你正確地閱讀它,它完全是完全錯誤的,不僅錯誤而且顯然是錯誤的。 怎么可能是對的? Java RMI不會, 實際上也不能以任何方式更改,刪除或擴展synchronized
的語義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.