2012-02-21 13 views
7

Para resumir, tengo problemas para cerrar un par de subprocesos no daemon de Java RMI después de que mi aplicación ya no necesite RMI. Esto evita que la JVM salga cuando se completa main().Los subprocesos de RMI impiden que JVM salga después de que main() complete

Entiendo que exportar UnicastRemoteObject s hará que RMI deje abiertos los hilos hasta que llame con éxito al UnicastRemoteObject.unexportObject(Object o,boolean force). He aquí un ejemplo (correr sin modificación y la JVM saldrá normalmente - quitar la llamada a unexportObject y la JVM Nunca salida):

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"); 
} 
} 

Además, no parece importar si se crea el registro y/o vincular el objeto remoto a él: lo único que parece importar en este ejemplo es que cada vez que creas un UnicastRemoteObject, debes llamar al unexportObject para evitar que se queden hilos después de que hayas terminado.

En mi aplicación, me he asegurado de haber llamado unexportObject en cada UnicastRemoteObject que creo, y aún el subproceso "reaper" de RMI y el subproceso de "conexión aceptada" aún persisten, impidiendo que mi JVM salga cuando mi aplicación terminado de usar los recursos de RMI.

¿Hay algo más que pueda hacer que RMI deje hilos, aparte de olvidarse de UnicastRemoteObjects? lo suficientemente

+0

¿Se supone que ese programa de prueba se cuelga? ¿Qué JRE estás usando? ¿Has probado> = 1.6? ¿Son los "reaper" y "connection-accept" realmente los únicos hilos no-daemon que quedan? – Gray

+0

Sí, esos dos hilos son los únicos que quedan cuando perfilo la aplicación. Se supone que el programa de prueba continuará ejecutándose después de que finalice el proceso principal, cuando usted comente la llamada a 'UnicastRemoteObject.unexportObject (obj, true)'. El comportamiento deseado es que el programa de prueba salga. Sospecho que probablemente me esté perdiendo una llamada a unexportObject en algún lugar, pero era curioso si hay otras formas de dejar en ejecución los hilos RMI. – CodeBlind

+0

Y sí, estoy ejecutando Java 1.6 y 1.7, el comportamiento es el mismo en ambas versiones. – CodeBlind

Respuesta

7

Claro, tuve un error en el código que causó una de mis (muchos) UnicastRemoteObjects a no Unexport sí mismo cuando la aplicación de llamada se realiza utilizando la misma. Así que la respuesta es:

Unexporting todos UnicastRemoteObjects dentro de una JVM correr es suficiente para cerrar todos los hilos no demonio RMI.

7

Suena como usted ha resuelto un problema que @Ben pero para la posteridad, que pensé en promocionar mi comentario a una respuesta. Cada vez que tengo un tipo de patrón de registro/anulación de registro, me aseguro de administrarlos a través de un objeto singleton. De esta forma, tiene un lugar donde ir para descubrir qué objeto no se ha eliminado. Exponer esto en JMX también es una victoria.

Algo como el siguiente código sería bueno. Le permitirá iniciar sesión o consultar JMX para ver qué objetos se han vinculado al registro pero aún no se han desvinculado.

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)); 
     } 
    } 
} 
+0

No necesita el mapa local. El registro ya es un mapa. Puede implementar toda esta clase sin 'registeredMap'. – EJP

+0

Te estás perdiendo el punto @EJP. El mapa muestra qué cosas han sido registradas por la aplicación pero no registradas. – Gray

+0

Oh, ya veo. Hay un método 'list []'. Tendré que ver si también muestra objetos internos. Editaré mi respuesta. – Gray

Cuestiones relacionadas