A Real Quick and Clear Intro of Java RMI
Preface: This semester I’m taking the Distributed System course. It’s one of the best course I’ve ever taken in CMU. But that’s not point - the point is we use RMI a lot. We write our own version of RMI in C, and we use Java RMI to implement distributed systems. It’s really fascinating, let me introduce it –
What is RMI
RMI(Remote Procedure Call) technique is very useful in distributed system development. Basically, it allows us to call a function on a remote machine as if we’re calling a local function. It hides many details in the RMI interface, such as marshall and unmarshall packages, network transmission, etc.
This figure should be able to illustrate the basic idea of RMI:
In the figure, local machine A make a remote procedure call, and the function is actually being executed at a remote machine B. While B is executing the code, A waits, and when B finishes the function and return, A gets the returned result - as if the function was executed locally at A.
With that I believe you should have understood the essence of RMI. Now, to make a clarification, A and B can also be different processes locate on the same machine. From the perspective of A, it doesn’t need to know where is B, it doesn’t even need to know B exists - it just call the function, as if it’s a local function.
The Java RMI - Architecture
Let’s get to the point here. Java directly provides RMI interface in the java.rmi
package. Before looking at the code, here’s a rough illustration of how Java RMI works:
As you can see:
- There’re three roles:
- RegistryServer is responsible to managing the mapping from a service name to a service class
- A RMI provider can bind a class instance (with some requirement, which we’ll cover later) to a specific name inside a registry server, and
- A RMI user/client can download the corresponding class instance by looking up that name in the same registry server
- In a registry server, one name can only be mapped to one class instance, but the same class instance can be binded with multiple names. Multiple clients can use the same name to access the same class instance simultaneously
Here client A and B both have access to the class instance provided by RMI provider A. So when client A or B execute some method of that instance, the code is actually being executed at RMI Provider A. And client A and B can run the same method at the same time, if we assume that’s no thread synchronization issue in the class AccountManager, because RMI is multi-thread by default.
Show Me The Code
Alright, here are the minimum code to implement both the client and the RMI provider.
First of all, we need to have an object that can be binded to the registry. We need to first define an interface:
Notes:
- The interface must extends
java.rmi.Remote
- All methods defined in this interface must throw
java.rmi.RemoteException
Then, we write a class to implement this interface
Notes:
- This class implements the defined interface. But it must also extends
java.rmi.server.UnicastRemoteObject
- Recall that RMI in Java is multi-thread. Therefore I add
synchronized
to all methods to ensure consistency
And the QueueItem
is just a very simple class. But since this object will be passed through network during remote invocation, it must implements java.io.Serializable
.
Finally, we come to the server…
… and the client, which look up the interface from the registry server and use it
We start the server first, then when we start the clients we can get results like:
You can download the source code. Hope it helps :)