Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java RMI服务器自行关闭_Java_Multithreading_Rmi - Fatal编程技术网

Java RMI服务器自行关闭

Java RMI服务器自行关闭,java,multithreading,rmi,Java,Multithreading,Rmi,我正在编写一个Java客户机-服务器应用程序,它使用RMI进行通信。我的问题是,出于某种原因,RMI服务器只是自动关闭,没有异常或错误。我正在使用Netbeans,我运行了一个配置文件来查看线程。 您可以在所附的映像中看到应用程序作为GC守护进程和RMI Reaper线程的末尾完成执行的时间点。但是,即使在应用程序结束后,RMI TCP Accept-1099线程仍在运行。更让我困惑的是,在弹出信息消息(您可以在屏幕截图中看到)告诉我服务器已停止后,图中的线程继续更新,因此我再次尝试与客户端连

我正在编写一个Java客户机-服务器应用程序,它使用RMI进行通信。我的问题是,出于某种原因,RMI服务器只是自动关闭,没有异常或错误。我正在使用Netbeans,我运行了一个配置文件来查看线程。

您可以在所附的映像中看到应用程序作为GC守护进程和RMI Reaper线程的末尾完成执行的时间点。但是,即使在应用程序结束后,RMI TCP Accept-1099线程仍在运行。更让我困惑的是,在弹出信息消息(您可以在屏幕截图中看到)告诉我服务器已停止后,图中的线程继续更新,因此我再次尝试与客户端连接。虽然失败了,但我可以看到正在创建一个新的RMI线程(连接18)

我不知道如何调试这个问题,也不知道当RMI accept线程仍在运行时应用程序如何退出

更新:以下是服务器的主要方法:

/**
 * Main entry point.
 *
 * @param args the application arguments - unused.
 */
public static void main(String[] args) {

    try {
        System.setProperty("java.rmi.dgc.leaseValue", "30000");
        sServerProperties = new ServerProperties();
        System.setProperty("java.rmi.server.hostname", sServerProperties.
                getRmiServer());
        createRmiRegistry();
        ConfigCore configCore = new ConfigCore();
        ServerCore server = new ServerCore(configCore);
        LoginHandler loginHandler = new LoginHandler(server);
        sRegistry.
                bind(Login.class.getSimpleName(), loginHandler.getRemote());

        Logger.log(Level.INFO, "Server ready!");
    } catch (RemoteException ex) {
        Logger.log(Level.SEVERE, "Unable to start RMI registry", ex);
    } catch (SQLException ex) {
        Logger.log(Level.SEVERE, "Unable to connect to the MySQL server",
                ex);
        System.err.println(ex.getMessage());
    } catch (IOException ex) {
        Logger.log(Level.SEVERE, "Unable to load or write properties file",
                ex);
        System.err.println(ex.getMessage());
    } catch (AlreadyBoundException ex) {
        Logger.log(Level.SEVERE, "RMI port already bounded", ex);
    } catch (NoSuchAlgorithmException ex) {
        Logger.log(Level.SEVERE, "Unable to digest password", ex);
    }
}

/**
 * Creates the RMI registry.
 *
 * @throws RemoteException if the RMI registry could not be created.
 */
private static void createRmiRegistry() throws RemoteException {
    if (sRegistry == null) {
        Logger.log(Level.INFO, "Creating RMI Registry...");
        sRegistry = LocateRegistry.createRegistry(sServerProperties.
                getRmiPort());
    }
}

这是RMI的常见问题。您需要将对实现的引用保存为类字段,这样它就不会得到GC。您还需要保持该类(带有main())的活动状态

我用这句话作为永无止境的口号:

for(;;) LockSupport.park(); 

您可以做任何您想做的事情,这样实现保持活动状态,而main()类保持活动状态。

您将看到VM在其最后一个非守护进程线程退出时退出的交互,以及热点垃圾收集行为、RMI的导出行为和在NetBeans探查器下运行JVM

主线程在
main()
方法返回后退出。但是,您已经导出了一个RMI服务器对象,因此只要存在活动的导出对象,RMI就会通过运行“RMI收割机”线程(非守护进程)使JVM保持活动状态。RMI通过在it对象表中仅保留对导出对象的弱引用来确定导出对象是否“活动”

不幸的是,通过查看
main()
方法,您的RMI服务器对象似乎仅通过局部变量引用。因此,它迟早会被垃圾收集,但在RMI的对象表中对它的引用较弱。当对象变得弱可及时,RMI收割机将其取消导出并退出。因为RMI收割机是最后一个非守护进程线程,所以JVM退出

请注意,RMI注册表是经过特殊处理的。导出注册表不会使JVM保持活动状态

还要注意的是,在
main()
方法的末尾放置一个无限循环将不一定会阻止RMI服务器对象未报告和GC。原因是,当对象变得不可访问时,对象会受到GC的约束,而活动方法的局部变量中存在的引用不足以使其可访问。看看关于那个话题的另一个问题。当然,将无限循环放入
main()
将阻止JVM退出,因为它使主线程保持活动状态,并且主线程不是守护线程

为了防止RMI服务器未被报告,通常在静态字段中存储对它的引用就足够了

现在,为什么JVM在探查器下运行时仍然存在?这只是分析器工作方式的产物。探查器检测到最后一个非守护进程线程已退出(而不是代表探查器在JVM中运行的其他线程),因此,此时它会弹出一个对话框,显示“探查的应用程序已完成执行”。不过,它会使JVM保持活动状态,以便您可以继续从中获取数据;这会产生副作用,使所有守护进程线程保持活动状态。您已经导出了一个注册表,因此它将继续侦听端口1099。当JVM处于这种状态时,如果您尝试,您可能仍然能够注册RMI对象。您的RMI服务器对象很久以来一直未被报告和GC'd,因此对它的请求将无法工作。但这就是为什么在JVM处于这种状态时仍然接受RMI连接的原因


底线是,确保您的RMI服务器对象没有得到GC'd。这样做的一个好方法是确保可以从静态字段访问它们。

您的应用程序是否处于无限循环中?如何确保
main
线程未完成?导出并绑定RMI存根后,主线程立即完成。应用程序只应在关闭所有线程后完成,而不仅仅是关闭主线程。主线程是线程图中的第一个条形图,您可以看到它立即关闭。所有非守护进程线程。好的,那么为什么应用程序在主线程完成后不立即关闭?@EJP至少在JDK 8中,RMI accept线程是守护进程线程。这在过去可能有所不同,但它们已经是守护进程线程很长一段时间了。他需要将注册表对象保存为静态对象!为了防止它被GC攻击,他似乎正在这么做。我正在保存所有导出的引用。我没有意识到我需要保持主要的运行。事实上,我曾经在绑定登录存根后做过Main.class.wait(),但仍然没有用,服务器一直在随机关闭。@EJP我做RMI的时间没有你长,但16年就快到了。和往常一样,很高兴再次与你交谈。我以前也遇到过同样的问题,我所做的,如上所述,是为了让服务器保持活力。我确实保留了一个对存根的引用,但这是一个不需要思考的问题。OP wait()可能会出现虚假唤醒,因此请使用park()。如果这不能解决您的问题,那么您还有另一个问题。它可以使服务器保持活动状态,但没有必要使服务器保持活动状态。他不需要这么做,等等。(1) 注册处没有得到特别处理。如果不静态存储,它可以像其他任何东西一样获得GCd。(2) OP的远程对象绑定在注册表中,这会导致DGC租赁,这会导致强本地引用,这会导致