2011-11-07 43 views
4

我現在使用LocateRegistry.createRegistry(1099)而不是在外部進程中使用註冊表。然而,註冊表在主程序結束後死亡。例如,如果我創建一個簡單的程序來創建註冊表,它將無法工作,因爲在主executino代碼結束之後。我期待LocateRegistry代碼創建一個線程,但似乎並非如此。這是使用LocateRegistry的正常行爲還是我錯過了什麼?RMI服務器不會使用LocateRegistry.createRegistry方法進行線程和死亡

代碼示例:

// ommited imports 

public class RMITest { 
    public static void main(String[] args) { 
     LocateRegistry.createRegistry(1099); 
     // JVM will exit now!!! 
    } 
} 

RMI服務器啓動和突然死亡。如何

回答

8

我期待LocateRegistry代碼來創建一個線程

這不是那麼簡單。

  1. 導出一個新的端口上的第一個對象創建該端口上偵聽線程,並且取消導出的最後一個對象端口上監聽導致該線程退出。這適用於所有遠程對象,而不僅僅是本地註冊表對象。

  2. 可通過本地GC自動發生未記錄,而本地GC可由遠程DGC觸發。

你的JVM退出,因爲你不是通過儲蓄在LocateRegistry.createRegistry()一個靜態變量返回的值,所以它得到GC'd,所以對象被導出,所以有出口端口1099沒有遠程對象,所以在1099上監聽的線程退出,所以沒有非守護線程,所以JVM退出。

解決方案:將LocateRegistry.createRegistry()的結果存儲在一個靜態變量中。當你希望你的JVM退出時,你可以使用它來取消導出註冊表。

+0

它的工作;) - 謝謝 –

+0

這幫了我很多。我在調試期間想知道爲什麼有這麼多的運行守護進程RMI線程。原因:每次我啓動一臺服務器時,我都將其存儲在匿名端口上。 – motaa

0
LocateRegistry.createRegistry(1099); 

創建一個新的守護線程命名我的機器上RMI TCP Accept-1099。此線程基本上在1099上監聽新的TCP/IP連接。

當JVM退出時,守護程序線程會自動終止。在您離開時,JVM會退出main()方法。更準確地說 - 當沒有更多的非守護進程線程時退出 - 顯然應用程序中只有一個非守護進程線程(名爲main)。

所以,你有兩個選擇:

  • 不要讓main()方法通過增加無限sleep()完成。
  • 創建一些非守護線程。當然,只有當線程實際上做了一些有用的事情而不是阻止JVM退出時才這樣做。
+0

它創建* non-daemon *線程。看到我的答案。 -1。 – EJP

4

有兩種可能的方式來啓動RMI註冊表。

  1. LocateRegistry.createRegistry(1099);執行註冊表的Java應用程序不能完成。在你的情況下,你可以啓動一個新的「永不結束」線程(參見下面的源代碼)
  2. rmiregistry這是一個包含在啓動RMI註冊表服務的Java分發版中的工具。請參閱rmiregistry - The Java Remote Object Registry

RMI註冊服務器的示例代碼。

import java.io.IOException; 
import java.rmi.RemoteException; 
import java.rmi.registry.LocateRegistry; 

public class RmiTest { 

    public static void main(String[] args) throws IOException { 
     final Object monitor = new Object(); 

     new Thread(new Runnable() { 
      public void run() { 
       try { 
        LocateRegistry.createRegistry(1099); 
        synchronized (monitor) { 
         monitor.wait();       
        } 
       } catch (RemoteException e) { 
        e.printStackTrace(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
       System.out.println("RMI Registry Thread finished."); 
      } 
     }, "RMI Registry Thread").start(); 
     System.out.println("Press enter to exit..."); 
     System.in.read(); 
     synchronized (monitor) { 
      monitor.notify();    
     } 
    } 
} 
+1

您的代碼容易受到虛假喚醒。即使通知尚未被調用,等待的線程也可以停止等待。您應該循環並檢查標誌,並且主線程應更改標誌值並通知。或者你可以使用初始化爲1的CountDownLatch。注意,我沒有看到在阻塞的新線程中啓動註冊表的要點,因爲主線程也被阻塞。 –

+0

你不需要這一切,我懷疑它真的解決了這個問題。看到我的答案。 – EJP

+0

是的,你是對的@EJP。這就足夠了:'LocateRegistry.createRegistry(1099); System.out.println(「Press enter to exit ...」); System.in.read();'。我想到了一個應用程序,首先啓動它自己的註冊表,然後可能執行一些其他代碼... – andy