分散アプリケーションをコード化するためにJava RMIを使用する方法を学習しています。 私はいくつかのことをテストするための単純なプログラムを書いています。クライアントを介して整数をサーバに渡すだけで、サーバはそれらを静的変数に蓄積します。ここでは、コードは次のようになります。RMIは自動的に「スレッドセーフ」ですか?
サーバー:
public class Adder extends UnicastRemoteObject implements IAdder {
/**
*
*/
private static final long serialVersionUID = 8229278619948724254L;
private static Integer sum = 0;
static Logger logger = Logger.getLogger("global");
protected Adder() throws RemoteException {
super();
// TODO Auto-generated constructor stub
}
@Override
public void add(int i) throws RemoteException {
System.out.println("Got: " + i);
synchronized (sum) {
sum += i;
System.out.println("The new sum is: " + sum);
}
}
@Override
public int result() throws RemoteException {
System.out.println("The sum is: " + sum);
return sum;
}
public static void main(String[] args) {
System.setSecurityManager(new SecurityManager());
try {
logger.info("Building remote object");
Adder obj = new Adder();
logger.info("Binding");
Naming.rebind("SommaServer", obj);
logger.info("Ready");
} catch (Exception e) {
e.printStackTrace();
}
}
}
クライアント:私は2つのクライアントスレッドを作成し、それらを実行し、クライアントのメインで
public class Client extends Thread {
static Logger logger = Logger.getLogger("global");
private IAdder obj;
private int array[] = new int[3];
public static void main(String[] args) {
try {
Client c1 = new Client(1);
Client c2 = new Client(2);
c1.start();
c2.start();
} catch (Exception e) {
e.printStackTrace();
}
}
public void work(int i) throws RemoteException {
obj.add(i);
}
public void run() {
Random rn = new Random();
try {
work(array[0]);
work(array[1]);
work(array[2]);
} catch (Exception e) {
e.printStackTrace();
}
}
public Client(int i) throws Exception {
if (i == 1) {
array[0] = 1;
array[1] = 3;
array[2] = 4;
}
if (i == 2) {
array[0] = 7;
array[1] = 2;
array[2] = 5;
}
logger.info("Remote object lookup");
obj = (IAdder) Naming.lookup("rmi://localhost/SommaServer");
}
}
(なし同期のチェックはありません私は、知っている、しかし私は物事を試している)。各スレッドには、サーバーに供給される数値の配列があります。 サーバーはそれを受信し、すべてのtogheterを追加します。
私はスレッドを扱っているので、最初の考えでは、合計の更新にロックを使用する必要がありました。そうしないと、スレッドのインターリーブのためにエラーが発生する可能性があります。したがって、サーバ内の同期ブロック。
しかし、何が起こるかを見るために、ブロックを削除しましたが、私はまだ正しい結果を得ていました(値は22です)。
ちょうど私がローカル変数を更新しすぎて、クライアントの「ローカル」バージョン、作ら確かに:私は、様々な数(8を取得せずに、私は、正しい結果を得る同期して
public class Client extends Thread {
private static Integer sum = 0;
static Logger logger = Logger.getLogger("global");
private IAdder obj;
private int array[] = new int[3];
public static void main(String[] args) {
try {
Client c1 = new Client(1);
Client c2 = new Client(2);
c1.start();
c2.start();
c1.join();
c2.join();
System.out.println("Ricevuto: " + sum);
} catch (Exception e) {
e.printStackTrace();
}
}
public void work(int i) throws RemoteException {
//obj.add(i);
synchronized(sum) {
sum += i;
}
}
public void run() {
Random rn = new Random();
try {
work(array[0]);
work(array[1]);
work(array[2]);
} catch (Exception e) {
e.printStackTrace();
}
}
public Client(int i) throws Exception {
if (i == 1) {
array[0] = 1;
array[1] = 3;
array[2] = 4;
}
if (i == 2) {
array[0] = 7;
array[1] = 2;
array[2] = 5;
}
}
}
を、15 、14、22 ...)
どういうことが起こっているのですか?私はRMIがスレッドセーフであることに疑いがあります。
その他の質問:RMIでオブジェクトをバインドすると、どのようにバインドされているのですか? Naming.rebind()を呼び出すオブジェクトの特定のインスタンス、またはクラス(そして、それを見てみると、ただ新しいインスタンスが得られますか?)
私はそれを逃した! – Paul
私はそれが私の主張であり、同期なしで(私は修正しました、ありがとう)、それは正しく動作しませんか?サーバーへの呼び出しが順不同であっても、最終結果は正しいと思いますが、書き込みが同期化されているかのように、それは私を捨ててしまいます。 – Paul
再び、欠陥のあるロジック。シンプルなテストではうまく動作しませんが、同期は「スレッドセーフです」という意味ではありません。単に失敗させる方法を見つけていないことを意味します。多くの異なるスレッドから数百万回ではなく数百万回を呼び出し、いくつかのプロセスで実行していると、おそらく失敗が見られるでしょう。例はスレッドセーフではないことを証明するのに十分です。スレッドセーフであることを証明するために、例は十分ではありません。目を閉じて道路を横切って生きているのと同じように、目を閉じて道路を横切ることが安全であることを証明していません。 –