RMI Server won't thread and dies with LocateRegistry.createRegistry method
Asked Answered
D

3

5

I'm now using LocateRegistry.createRegistry(1099) rathern than using the registry in a external process. However the registry dies after the main program ends. For instance, if I make a simple program that creates the registry it'll not work because after the main executino the code ends. I was expecting the LocateRegistry code to create a thread, but it seems that this is not the case. Is this the normal behavior of using LocateRegistry or I'm missing something?

Code sample:

// ommited imports

public class RMITest {
    public static void main(String[] args) {
        LocateRegistry.createRegistry(1099);
        // JVM will exit now!!!
    }
}

The RMI Server start and suddenly dies. How

Draughty answered 7/11, 2011 at 21:10 Comment(0)
C
8

I was expecting the LocateRegistry code to create a thread

It's not that simple.

  1. Exporting the first object on a new port creates a thread that listens on that port, and unexporting the last object listening on a port causes that thread to exit. This is for all remote objects, not just local Registry objects.

  2. Unexporting can happen automatically via local GC, which in turn can be trigged by remote DGC.

Your JVM exits because you aren't saving the value returned by LocateRegistry.createRegistry() in a static variable, so it gets GC'd, so the object gets unexported, so there are no remote objects exported on port 1099, so the thread that listens on 1099 exits, so there are no non-daemon threads, so the JVM exits.

Solution: store the result of LocateRegistry.createRegistry() in a static variable. You can use that to unexport the Registry when you want your JVM to exit.

Corrade answered 8/11, 2011 at 0:31 Comment(1)
This helped me a lot. I was wondering during my debugging session why there were so many running Daemon RMI Threads. Reason: everytime I launched a server I exported it's stub on an anonymous port.Charcuterie
G
4

There are two possible ways to start the RMI registry.

  1. LocateRegistry.createRegistry(1099); The java application executing the registry must not finish. In your case you could start a new "never ending" thread (see below for source code)
  2. rmiregistry This is a tool included in the java distribution that starts an RMI registry service. see rmiregistry - The Java Remote Object Registry

Sample code for RMI registry server.

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();            
        }
    }
}
Gaddis answered 7/11, 2011 at 21:55 Comment(4)
Your code is vulnerable to spurious wakeups. The waiting thread could stop waiting even if notify has not been called. You should loop and check for a flag, and the main thread should change the flag value and notify. Or you could use a CountDownLatch initialized to 1. Note that I don't see the point of starting the registry in a new thread which blocks, since the main thread is blocked as well.Foramen
You don't need all this, and I doubt that it really solves the problem. See my answer.Corrade
Yes, you are right @EJP. This would be sufficient: LocateRegistry.createRegistry(1099); System.out.println("Press enter to exit..."); System.in.read();. I thought of an application that first starts its own registry and then maybe executes some other code...Gaddis
@AndreasKnees you don't need all that either. Just save the return value and unexport it when done.Corrade
A
0
LocateRegistry.createRegistry(1099);

creates a new daemon thread named RMI TCP Accept-1099 on my machine. This thread essentially listens for new TCP/IP connections on 1099.

Daemon threads are automatically killed when JVM exits. And in your case JVM exits when you leave main() method. More precisely - it exits when there are no more non-daemon threads - and apparently there is only one non-daemon thread in your application (named main).

So you have two options:

  • don't let main() method to finish by adding infinite sleep().
  • create some non-daemon thread. Of course only do this when the thread actually does something useful rather than preventing JVM to exit.
Aiguille answered 7/11, 2011 at 21:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.