Java RMI - я не понимаю, почему нет общего состояния - PullRequest
1 голос
/ 10 января 2012

У меня проблема (может быть, проблема фундаментального понимания) с Java RMI.У меня есть объект "сервер" и человек "клиенты".Оба являются объектами RMI (они реализуются для различных интерфейсов Remote).Клиенты регистрируются на сервере и сохраняются в списке.Сервер позже распределит некоторую работу клиентам и извлечет результат.

Проблема в том, что список, в котором хранятся клиенты, кажется не общим (у меня нетлучшее описание).Т.е. если один клиент вызывает интерфейс сервера и регистрируется сам, он будет добавлен в список, но вызов, по-видимому, будет выполняться только локально.

Ниже приведен минимальный пример кода:

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, он будет выводить «Сервер видит: 0» в цикле.Если я теперь запускаю клиент java Client в другой оболочке, я получаю «В удаленном вызове: 1».Однако процесс сервера все еще выводит «Сервер видит: 0».

Почему это так?Что я делаю неправильно?Я действительно думал, что понял Java RMI: (

Ответы [ 2 ]

2 голосов
/ 10 января 2012

Ваш 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».

0 голосов
/ 10 января 2012

Попробуйте изменить:

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