我对Java RMI有一个问题(可能是一个基本的理解问题)。我有一个"服务器"对象和人的"客户端"。两者都是RMI对象(它们实现到不同的远程接口)。客户端在服务器上自行注册,并存储在列表中。服务器稍后将向客户端分发一些工作并获取结果。
问题是,存储客户端的列表似乎不是共享的(我没有更好的描述)。也就是说,如果一个客户端调用服务器接口并注册自己,它将被添加到列表中,但调用似乎只是本地的。
以下是代码的最小示例:
IRemote.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface IRemote extends Remote {
public void remoteCall() throws RemoteException;
}
RemoteImple.java
import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.ArrayList;
public class RemoteImpl implements IRemote, Serializable {
public ArrayList<Integer> list = new ArrayList<Integer>();
@Override
public void remoteCall() throws RemoteException {
list.add(23);
System.out.println("In remote call: "+list.size());
}
}
RegAndServer.java
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class RegAndServer {
public static void main(String[] args) throws RemoteException, InterruptedException {
Registry reg = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
RemoteImpl impl = new RemoteImpl();
reg.rebind("server", impl);
while(true) {
Thread.sleep(2000);
System.out.println("Server sees: "+impl.list.size());
}
}
}
Client.java
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class Client {
public static void main(String[] args) throws MalformedURLException, RemoteException, NotBoundException {
IRemote remote = (IRemote) Naming.lookup("//localhost/server");
remote.remoteCall();
}
}
如果我启动服务器java RegAndServer
,它将在循环中输出"server sees:0"。如果我现在在另一个shell中启动客户端java Client
,我会得到"in remote call:1"。但是,服务器进程仍然输出"服务器看到:0"。
为什么会这样?我做错了什么?事实上,我以为我已经理解了Java RMI:(
您的RemoteImpl
不应该是Serializable
(您不想通过网络发送它的副本,只想发送存根,运行时会为您这样做),并且必须扩展UnicastRemoteObject
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
public class RemoteImpl extends UnicastRemoteObject implements IRemote {
public ArrayList<Integer> list = new ArrayList<Integer>();
public RemoteImpl() throws RemoteException {
}
@Override
public void remoteCall() throws RemoteException {
list.add(23);
System.out.println("In remote call: "+list.size());
}
}
请记住,代码是在服务器端执行的,即使调用是从客户端进行的,因此消息"in remote call"将显示在服务器日志中。
尝试更改:
public ArrayList<Integer> list = new ArrayList<Integer>();
至
public static ArrayList<Integer> list = new ArrayList<Integer>();
如果有帮助的话。确保安全:
public class RemoteImpl implements IRemote, Serializable {
private static volatile ArrayList<Integer> list = new ArrayList<Integer>();
@Override
public void remoteCall() throws RemoteException {
synchronized(list) {
list.add(23);
}
System.out.println("In remote call: "+list.size());
}
}