我有一个问题(可能是一个基本的理解问题),使用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
,我会收到“在远程调用中:1”。但是,服务器进程仍然输出“Server sees:0”。
这是为什么?我究竟做错了什么?我实际上认为我已经理解了Java RMI :(
答案 0 :(得分:2)
您的RemoteImpl
不应该是Serializable
(您不希望通过网络发送它的副本,只是存根,运行时会为您发送),并且必须扩展UnicastRemoteObject
{1}}
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());
}
}
请记住,即使从客户端进行呼叫,代码也会在服务器端执行,因此“远程呼叫”消息将显示在服务器日志中。
答案 1 :(得分:0)
尝试改变:
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());
}
}