2012-01-10 13 views
1

Java RMIで問題が発生している可能性があります。私は "サーバー"オブジェクトと人 "クライアント"を持っています。どちらもRMIオブジェクトです(異なるリモートインタフェースに実装されています)。クライアントは自分自身をサーバーに登録し、リストに格納されます。サーバーは後でいくつかの作業をクライアントに配布し、結果を取得します。Java RMI - 共有状態が存在しない理由を理解できません

問題は、クライアントが保存されているリストは、であるとは思われません。(これ以上の説明はありません)。私。 1つのクライアントがサーバーインターフェイスを呼び出して自分自身を登録すると、それがリストに追加されますが、その呼び出しはローカルにしか見えません。続い

は、コードの最小の例である:

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を別のシェルで起動すると、 "In remote call:1"と表示されます。しかし、サーバープロセスは "Server sees:0"を出力します。

これはなぜですか?私は間違って何をしていますか?私は実際に私が変更するためのJava RMI :(

+0

リストを 'RemoteImpl'ではなく' RegAndServer'に入れてそこから使うと、それは機能しますか?私はわからないが、 'RemoteImpl'オブジェクトが毎回生成されるようだ。 – Viruzzo

+0

いいえ@Viruzzo、どちらもうまくいきません。 –

答えて

2

あなたRemoteImplSerializableであるべきではありません(ネットワーク経由、スタブだけ、またはDランタイムは、そのあなたのために)し、そしてコールがクライアントから作られていても、コードはサーバ側で実行されていることに注意してください、そうリモートコールでメッセージ」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()); 
    } 
} 

を拡張する必要があります"がサーバーログに表示されます。

+0

これはそれでした。いいえ、私はこれを見ています。私は過去にUnicastRemoteObjectを使用していたことは確かです。 –

+0

ええ、RMIのすべての特徴を覚えておくのは難しいです。 (私は、スケルトンとスタブを手作業でコンパイルして配布しなければならなかったとき、rmiregistryを開始したとき、コードベースのフラグをセットしなければならない時を思い出しました...)。 – fortran

+0

@fortranこれは、この特定の点で決して変更されていません。 – EJP

0

てみてください理解していたと思った:それは助け場合

public static ArrayList<Integer> list = new ArrayList<Integer>(); 

public 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()); 
    } 
} 
+0

いいえ、動作しません。 –

+0

Hmm。本当に驚くべきことです。 "list"はJVM全体のインスタンスです。可能性のあるリストの再初期化を避けるために、リスト宣言に「final」を追加できますか? ( "private static final volatile ArrayList list = new ArrayList ();") – andrey

関連する問題