The 10 minutes “Getting started with RMI” tutorial
As a result, writing distributed or client-server applications becomes trivial. Let’s see a very minimalistic example.
Our scenario will have a server sharing an object via RMI and a client calling the shared instance.
First we need to define the interface for our remote object. In our case it is a simple interface for incrementing a shared counter.
Api.java
package com.littletutorials.rmi.api;
import java.rmi.*;
public interface Api extends Remote {
public Data incrementCounter(Data value) throws RemoteException;
}
Notice the fact that our interface implements java.rmi.Remote to mark the interface as available remotely. Also the interface uses a Data class to hold data. The purpose of this class in this tutorial is only to show how to send your own objects across the wire. In itself it doesn’t add any value over an int.
Data.java
package com.littletutorials.rmi.api;
import java.io.*;
public class Data implements Serializable {
private static final long serialVersionUID = 1L;
private int value;
public Data(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
The Data class implements java.io.Serializable to specify that its instances can be sent across the network.
And here is the implementation for our shared counter:
ApiImpl.java
package com.littletutorials.rmi.server;
import java.rmi.*;
import java.rmi.server.*;
import com.littletutorials.rmi.api.*;
public class ApiImpl extends UnicastRemoteObject implements Api {
private static final long serialVersionUID = 1L;
private int counter = 0;
public ApiImpl() throws RemoteException {
super();
}
@Override
public synchronized Data incrementCounter(Data value) throws RemoteException {
counter += value.getValue();
return new Data(counter);
}
}
Notice that I decided to extend UnicastRemoteObject to have my object automatically exported for RMI access with JRMP (Java Remote Method Protocol). If you don’t want to extend this class or you cannot because you need to extend some other class you could call:
UnicastRemoteObject.exportObject(this);
But keep in mind, in this case you have to generate your stub using rmic!
Now it is time to write the server application
Server.java
package com.littletutorials.rmi.server;
import java.rmi.*;
import java.rmi.registry.*;
import com.littletutorials.rmi.api.*;
public class Server {
private static final int PORT = 1099;
private static Registry registry;
public static void startRegistry() throws RemoteException {
// create in server registry
registry = java.rmi.registry.LocateRegistry.createRegistry(PORT);
}
public static void registerObject(String name, Remote remoteObj)
throws RemoteException, AlreadyBoundException {
registry.bind(name, remoteObj);
System.out.println("Registered: " + name + " -> " +
remoteObj.getClass().getName() + "[" + remoteObj + "]");
}
public static void main(String[] args) throws Exception {
startRegistry();
registerObject(Api.class.getSimpleName(), new ApiImpl());
Thread.sleep(5 * 60 * 1000);
}
}
Usually most of the examples require the rmiregistry to be started as a separate process. But, since this tutorial is about simpler ways, we create the RMI registry “in-process“. Then we register an instance of the API implementation with our registry. As instance name we use the API interface class name.
The only piece of the puzzle remains the client code:
Client.java
package com.littletutorials.rmi.client;
import java.rmi.registry.*;
import com.littletutorials.rmi.api.*;
public class Client {
private static final String HOST = "localhost";
private static final int PORT = 1099;
private static Registry registry;
public static void main(String[] args) throws Exception {
registry = LocateRegistry.getRegistry(HOST, PORT);
Api remoteApi = (Api) registry.lookup(Api.class.getSimpleName());
for (int i = 1; i <= 100; i++) {
System.out.println("counter = " +
remoteApi.incrementCounter(new Data(1)).getValue());
Thread.sleep(100);
}
}
}
An this is it. You can now start the server and the clients!
To deploy this code on different machines you need to create 3 jar files:
api.jar: Api.java, Data.java
server.jar: Server.java, ApiImpl.java
client.jar: Client.java
On the server machine the class path will contain api.jar and server.jar
On the client machine the class path will contain api.jar and client.jar
Notes:
- It is your responsibility to make the remote objects thread safe
- This example is not production code. For example there is no exception handling
- It is possible to download the shared code in api.jar at runtime from an HTTP server but this is beyond the purpose of this short tutorial

Why Api extends Serializable?? You don’t expect the service itself to be transferred over the wire, do you? (I don’t know much about RMI, but I don’t think rmiregistry offers persistence for remote objects, which would make Serializable a sensible requirement).
Why ApiImpl ctor throws RemoteException??
@ Dimitris Andreou
You are right, it doesn’t make sense. The
Serializablewas a leftover from a more complex example. I changed the tutorial to show how to useSerializablewith RMI.The constructor throws
RemoteExceptionbecausesuper()throwsRemoteException. Since thesuper()call has to be the first statement in the constructor you cannot mask this exception.On the client side, can the remoteApi object be shared across threads ? (Assuming the implmentation is threadsafe. Are there any limitations to this ?
Rajeev
Hi!
Thanks very much for your example. It’s been very helpful!
I’ve got one question, why the server class launches a Thread.sleep(5 * 60 * 1000) instruction?
Diego
Hello! Your tutorial has been most helpful. I have a question: Why doesn’t your example require to meddle with java.policy files or with the System Security Manager?
Thanks!