Java RMI - 我不明白为什么没有共享状态

时间:2012-01-10 11:30:41

标签: java rmi

我有一个问题(可能是一个基本的理解问题),使用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 :(

2 个答案:

答案 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());
    }
}