2011-11-07 42 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