Потоки RMI препятствуют выходу JVM после завершения main () - PullRequest
9 голосов
/ 22 февраля 2012

Короче говоря, у меня возникли проблемы с закрытием нескольких потоков, не являющихся демонами Java RMI, после того как мое приложение больше не нуждается в RMI.Это предотвращает выход JVM после завершения main ().

Я понимаю, что экспорт UnicastRemoteObject s заставит RMI оставить потоки открытыми, пока вы не вызовете UnicastRemoteObject.unexportObject(Object o,boolean force).Вот пример (запускается без изменений, и JVM завершает свою работу нормально - удалите вызов uninportObject, и JVM никогда не завершит работу):

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

Кроме того, не важно, создаете ли вы реестри / или привязать к нему удаленный объект - единственное, что, кажется, имеет значение в этом примере, - это то, что каждый раз, когда вы создаете UnicastRemoteObject, вам нужно вызывать unexportObject, чтобы предотвратить сохранение потоков после того, как вы закончите.

В своем приложении я удостоверился, что вызывалexportObject для каждого создаваемого мной UnicastRemoteObject, и все же поток RMI "reaper" и поток "connection accept" все еще сохраняются, предотвращая выход моей JVM, когда мойПриложение завершено с использованием ресурсов RMI.

Есть ли что-то еще, что может привести к тому, что RMI оставит потоки позади, кроме того, что забудет удалить UnicastRemoteObjects?

Ответы [ 2 ]

7 голосов
/ 22 февраля 2012

Звучит так, как будто ты решил свою проблему @Ben, но для потомков я подумал, что я перейду свой комментарий к ответу. Всякий раз, когда у меня есть тип шаблона «зарегистрировать / отменить регистрацию», я обязательно управляю им через одноэлементный объект. Таким образом, у вас есть одно место, чтобы выяснить, какой объект не был незарегистрированным. Выявление этого в JMX также является победой.

Что-то вроде следующего кода было бы хорошо. Это позволит вам войти в систему или запросить JMX, чтобы увидеть, какие объекты были связаны с реестром, но еще не были связаны.

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 голосов
/ 22 февраля 2012

Конечно, у меня была ошибка в коде, из-за которой один из моих (многих) объектов UnicastRemoteObject не отключился, когда вызывающее приложение было выполнено с его использованием.Поэтому ответ таков:

Отмена всех объектов UnicastRemoteObject в работающей JVM достаточна для закрытия всех потоков, не являющихся демонами RMI.

...