RMI streams prevent JVM from exiting after completion of main ()

In short, I was having trouble getting multiple non-daemon Java-RMI threads to close after my application no longer needs RMI. This prevents the JVM from exiting when main () completes.

I understand that exporting UnicastRemoteObject will cause RMI to leave threads open until you get a call to UnicastRemoteObject.unexportObject(Object o,boolean force) . Here's an example (starting without modification and the JVM will exit fine - delete the call to unexportObject and the JVM will never exit):

 import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; public class TestUnicastRemoteObject{ private static UnicastRemoteObject obj; private static Registry registry; public static void main(String[] args) throws Exception{ obj = new UnicastRemoteObject(){ private static final long serialVersionUID = 1L; }; System.err.println("created UnicastRemoteObject"); System.err.println("creating registry ..."); registry = LocateRegistry.createRegistry(9999); System.err.println("registry created."); System.err.println("binding obj to registry ..."); registry.bind("Test", obj); System.err.println("bound"); UnicastRemoteObject.unexportObject(obj, true); System.err.println("unexported obj"); } } 

Also, it doesn't matter if you create a registry and / or bind a remote object to it - the only thing that seems to matter in this example is that every time you create a UnicastRemoteObject, you need to call unexportObject to prevent the remaining flows after completion.

In my application, I made sure that I called the unexportObject file for each UnicastRemoteObject created, but nonetheless, the RMI reaper stream and connection accept stream are still saved, which prevents my JVM from exiting when my application terminates using RMI resources.

Is there anything else that could make RMI leave threads except forgetting the UnicastRemoteObjects exception?

+7
source share
2 answers

Of course, I had a mistake in the code due to which one of my (many) UnicastRemoteObjects was not a non-exporter itself when the calling application was executed using it. So the answer is:

Unexporting all UnicastRemoteObjects in a running JVM is enough to close all non-RMI daemon threads.

+7
source

It looks like you solved the @Ben problem, but for posterity, I thought I would promote my comment on the answer. Whenever I have a registration / deregistration type, I am sure to manage them through a singleton object. Thus, you have one place to find out which object has not been unregistered. Revealing this in JMX is also a win.

Something like the following code would be nice. This will allow you to register or a JMX request to see which objects have been tied to the registry but have not yet been disconnected.

 public class UnicastRegistry { private static Registry registry; private static UnicastRegistry singleton; // private to force the singleton private UnicastRegistry() throws RemoteException { registry = LocateRegistry.createRegistry(9977); } public static UnicastRegistry createSingleton() throws RemoteException { if (singleton == null) { singleton = new UnicastRegistry(); } return singleton; } public void register(String label, Remote obj) throws Exception { registry.bind(label, obj); } public void unregister(String label) throws Exception { Remote remote = registry.lookup(label); registry.unbind(label); if (remote instanceof UnicastRemoteObject) { UnicastRemoteObject.unexportObject(remote, true); } } public void unregisterAll() throws Exception { for (String label : registry.list()) { unregister(label); } } public void printStillBound() throws Exception { String[] stillBound = registry.list(); if (stillBound.length > 0) { System.out.println("Still bound = " + Arrays.toString(stillBound)); } } } 
+7
source

All Articles