RMI Serializing Error
Jason Sicotte <[email protected]>
| Newsgroups | gmane.comp.java.sun.rmi |
|---|---|
| Message-ID | <LISTSERV%[email protected]> |
I would like to ask the RMI community what possible solutions are available
to the an issue I am experiencing. From what I can tell, RMI has an
inability to reliably pass a HashMap to a client. However, the problem only
occurs when said HashMap has been changed by another thread on the server.
The reason why this happens is because RMI does not obtain a lock on the
object before serializing. Thus, when the HashMap's writeObject() method is
called, the iteration fails.
The only Exception noticeable initially is an IOException on the client
side. If the application is run with the
"-Dsun.rmi.server.exceptionTrace=true" option, the true cause of the error
is apparent:
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$EntryIterator.next(Unknown Source)
at java.util.HashMap.writeObject(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
The serialization fails which prematurely aborts the data transfer, which
causes the IOException on the client end.
This error can easily be reproduced with the following two files:
// ServerInterface.java ///////////////////////////////////////////////////////
import java.rmi.*;
import java.util.Map;
public interface ServerInterface extends Remote{
public Map getMap() throws RemoteException;
}
// end ServerInterface.java ///////////////////////////////////////////////////
// RMIServer.java /////////////////////////////////////////////////////////////
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.util.*;
public class RMIServer extends UnicastRemoteObject implements
ServerInterface, Runnable{
volatile Map serverMap = Collections.synchronizedMap(new HashMap());
public RMIServer() throws Exception{
java.rmi.registry.LocateRegistry.createRegistry(1091);
Naming.rebind("//:1091/TestServer", this);
}
public void run(){
while(true){
synchronized(this.serverMap){
for(int i=0; i<10000 ; i++){
this.serverMap.put(new Integer(i),new Integer(i));
}
try{Thread.sleep(1000);}catch(InterruptedException e){}
}
synchronized(this.serverMap){
this.serverMap.clear();
}
}
}
public static void main(String[] args) throws Exception {
RMIServer server = new RMIServer();
Thread serverThread = new Thread(server);
serverThread.start();
RMIClient client = new RMIClient();
Thread clientThread = new Thread(client);
clientThread.start();
}
public Map getMap() throws RemoteException {
synchronized (this.serverMap){
return this.serverMap;
}
}
// RMIClient inner class
public static class RMIClient implements Runnable{
ServerInterface server = null;
public RMIClient(){
try{
this.server = (ServerInterface)Naming.lookup("//:1091/TestServer");
} catch (Exception e){
e.printStackTrace();
}
}
public void run(){
while(true){
try {
Map m = server.getMap();
try{Thread.sleep(1000);}catch(InterruptedException e){}
} catch (RemoteException e) {e.printStackTrace();}
}
}
}
}
//end RMIServer.java //////////////////////////////////////////////////////////
===========================================================================
To unsubscribe, send email to [email protected] and include in the body
of the message "signoff RMI-USERS". For general help, send email to
[email protected] and include in the body of the message "help".
For a list of frequently asked RMI questions please refer to:
http://java.sun.com/j2se/1.3/docs/guide/rmi/faq.html
To view past RMI-USERS postings, please see:
http://archives.java.sun.com/archives/rmi-users.html