2 回答

TA貢獻2051條經驗 獲得超10個贊
概述
這篇文章中似乎有一些問題,因此我將嘗試詳細介紹每個部分。
問題 1 - 可以以任何方式控制多線程嗎?
是的!多線程的實現可以是任何你想要的。一個RMI的實現僅僅是有足夠的抽象感覺到他們在1 JVM存在單獨的JVM之間的通信; 因此對多線程沒有影響,因為它只是通信層。
問題 2 - 是為每個遠程調用創建一個線程(在服務器端)還是使用線程池?
請參閱此處的文檔。如果它們在不同的線程上,簡短的回答是否定的。
由 RMI 運行時分派到遠程對象實現的方法可能會或可能不會在單獨的線程中執行。RMI 運行時不保證將遠程對象調用映射到線程。由于對同一個遠程對象的遠程方法調用可能并發執行,因此遠程對象實現需要確保其實現是線程安全的。
使用線程池的RMI取決于實現,但作為使用RMI的開發人員,這應該無關緊要,因為它封裝在RMI連接層中。
問題 3 - 使用RMI,如何確保某些RMI調用等待其他調用終止?
這是一個相當模糊的問題,但我認為您要問的是在RMI 中同步時如何正確阻止。這與您的應用程序設計有關。讓我們假設您嘗試訪問數據庫并且您必須同步數據庫訪問。如果客戶端嘗試通過RMI調用訪問,它將調用遠程服務器的方法來保存所有同步,因此如果必須的話等待鎖定。因此,客戶端將等待輪到它通過服務器訪問數據庫。因此,在您當前的場景中,您希望數據庫同步出現在服務器端。
問題 4 - 是否有另一種非 RMI 方法,具有相同的便利性和效率,可以更好地解決這個問題?
絕對地。以下是可用于通信的通信實現的簡要列表。
1) RESTful
2)RMI
3) 插座
4) gRPC
我的建議是使用 RESTful,因為它是最直接的,并且在互聯網上有大量的實現/文檔。效率似乎對您來說非常重要,但您的操作只是以標準方式操作數據庫。因此,我相信 Restful 實現將提供足夠的效率。
這樣想;您有 N 個客戶端、一個負載平衡器和 M 個服務器。客戶端和服務器之間不存在持續連接,從而降低了復雜性和計算量。隨著 N 個客戶端的增長,負載均衡器會創建更多的服務器實例并適當地分配負載。請注意,客戶端和服務器之間的請求實際上非常小,因為它們將具有有效負載和請求類型。此外,服務器將接收請求并正常并行計算操作。優化可以在服務器端通過線程池或 spring 等框架完成。

TA貢獻1895條經驗 獲得超7個贊
您要求的是一種根據任務的依賴關系協調任務執行的方法。您的任務進行 RMI 調用這一事實無關緊要。我們可以想象一個純粹的計算任務,它不訪問遠程機器并且仍然相互依賴,例如,通過提供在一個任務中計算的值作為其他任務的參數。
依賴任務的協調是異步編程的核心問題。JDK對異步編程的支持并不全面,但足以解決你的問題。您需要使用兩件事:CompletableFuture和一個Executor. 請注意,RMI 調用會阻塞它運行的線程,因此使用線程數有限的 Executor 會導致特定類型的死鎖,稱為“線程饑餓”,此時計算無法繼續,因為所有可用線程都被阻塞。因此,使用具有無限數量線程的執行程序,最簡單的是為每個任務創建新線程的執行程序:
Executor newThreadExecutor = (Runnable r)->new Thread(r).start();
然后,對于每個 RMI 調用(或任何其他任務),聲明任務方法。如果任務不依賴于其他任務,則該方法應該沒有參數。如果任務依賴于其他任務產生的結果,則聲明一個或兩個參數(CompletableFuture 不直接支持更多的參數)。讓我們有:
String m0a() {return "ok";} // no args
Integer m0b() {return 1;} // no args
Double m2(String arg, Integer arg2) {return arg2/2.0;} // 2 args
讓我們要計算以下結果:
String r0a = m0a();
Integer r0b = m0b();
Double r2 = m2(r0a, r0b);
但異步,這樣的呼吁m0a和m0b并行執行,并呼吁m2盡快啟動雙方m0a和m0b成品。
然后,將每個任務方法用一個實例包裹起來,CompletableFuture根據任務方法的簽名,使用不同的方法CompletableFuture:
CompletableFuture<String> t0a = CompletableFuture.supplyAsync(this::m0a, newThreadExecutor)
CompletableFuture<Integer> t0b = CompletableFuture.supplyAsync(this::m0b, newThreadExecutor)
CompletableFuture<Double> t2 = t0a.thenCombineAsync(t0b, this::m2, newThreadExecutor)
任務在聲明后立即開始執行,不需要調用特殊start方法。
要從最后一個任務中獲得最終結果t2,可以使用get()接口方法Future:
Double res = t2.get();
添加回答
舉報