6

Java RMI とスレッド同期について、実際に 2 つの質問があります。

1) RMI リモート メソッドを同期として実装した場合、それらは相互に排他的であることが保証されますか? RMI メソッド (クライアントに提供されるメソッド) が 2 つ同時に実行されないようにする必要があります。

2) サーバーが定期的に実行するメソッドがあります。クリーンアップを行うために使用されます。リモートクライアントによって実行/使用されているRMIメソッドがある場合、この特定のメソッドが実行されないようにする必要があります。また、そのメソッドが実行されているときは、RMI 呼び出しができないはずです。つまり、クライアントは待機する必要があります。どうすればそれを行うことができますか?ロックについて読んだことがありますが、このシナリオでロックを使用する方法がわかりません。

RMI メソッドを静的に実装し、そのクリーンアップ メソッドを RMI インターフェイス内に含めることを検討しましたが、問題を解決するエレガントな方法ではないようです。

また、RMI インターフェイス内のクリーンアップ メソッドを同期として記述しました。テストのために実行したところ、メソッド間に衝突はないように見えましたが、確信が持てません。

お時間とご回答ありがとうございます。

4

4 に答える 4

11

1) RMI リモート メソッドを同期として実装した場合、それらは相互に排他的であることが保証されますか? RMI メソッド (クライアントに提供されるメソッド) が 2 つ同時に実行されないようにする必要があります。

RMI は (EJB とは異なり) それ自体ではそのような保証を提供せず、何らかの同期を実装しない限り、同じリモート オブジェクトに対する 2 つの呼び出しが同時に実行される可能性があります。あなたのアプローチは正しいです。すべてのメソッドを同期すると、同じオブジェクトで同時に 2 つのメソッドが実行されないようになります。注: キーワードsynchronizedのみは と同等synchronized( this )です。

2) サーバーが定期的に実行するメソッドがあります。クリーンアップを行うために使用されます。リモートクライアントによって実行/使用されているRMIメソッドがある場合、この特定のメソッドが実行されないようにする必要があります。

クリーンアップ ジョブが別のクラスにある場合は、リモート オブジェクトとクリーンアップ ジョブの間で共有するロックを定義する必要があります。リモート オブジェクトで、ロックとして使用するインスタンス変数を定義します。

protected Object lock = new Object();

慣例により、人々はObjectこの目的で を使用します。synchronized( remoteObj.lock ) { ... }次に、同じパッケージにあると仮定して、定期的なジョブでロックを取得する必要があります。

リモート オブジェクトの他のメソッドは、同じ方法で同期する必要があります (synchronized単独では十分ではありません)。これにより、リモート メソッド呼び出しと定期的なジョブの両方が排他的になります。

RMI メソッドを静的に実装し、そのクリーンアップ メソッドを RMI インターフェイス内に含めることを検討しましたが、問題を解決するエレガントな方法ではないようです。

また、RMI インターフェイス内のクリーンアップ メソッドを同期として記述しました。テストのために実行したところ、メソッド間に衝突はないように見えましたが、確信が持てません。

よく分かりましたら、クリーンアップロジックを静的メソッドにしたいですか?単独の静的メソッドはsynchronized、クラスのロックを取得します。synchronizedオブジェクト インスタンスのロックを取得する「通常の」メソッド。これらは同じ暗黙のロックではありません!

しかし、インスタンス化されたリモート オブジェクトが1 つしかない場合は、ロックを静的にすることができます (これはクラスのロックと同じですが、少しクリーンです)。クリーンアップ コードも静的にすることができ、リモート オブジェクトと同じクラスにすることも、同じクラスにすることもできます。

スケルトン:

public class MyRemoteClass {
   public static Object lock = new Object();

   public void doStuff()
   {
       synchronized( lock ) { ... }
   }
}

public class Cleanup {
   public static void doIt()
   {
       synchronized( MyRemoteClass.lock ) { ... }
   }
}
于 2010-02-16T20:13:24.327 に答える
2
  1. RMI クライアントからの呼び出しごとに、RMI サーバーはその呼び出しを新しいスレッドで実行します。共有オブジェクトへのアクセスを同期するだけで済みます。

  2. 別のスレッドまたはタイマーは、サーバーがクライアント側からの呼び出しを受け入れるのを止めません。これには同期が必要です。ベスト プラクティスは、クリーンアップ ジョブの実行が中断される可能性があるか、または要求をキューに入れることができるかなどによって異なります。最も簡単な方法は、RMI メソッドがロックを待機するようにすることです。 ewernli によって説明されています。

編集:あなたのコメントによると、この種の基本的な同期を実現する方法を示すスケルトン。すべてが相互に排他的になっているため、複数のクライアントが関係する場合、高いパフォーマンスは期待できません。とにかく、これはあなたの要件をカバーします。(私は願います)。プロジェクトが成長する場合は、同時実行チュートリアルを読む必要があります

Object mutex = new Object();

int rmiMethod1() {
    synchronized (mutex) {
        doWhatNeeded1();
    }
}

int rmiMethod2() {
    synchronized (mutex) {
        doWhatNeeded2();
    }
}

// in your cleanup thread
void run() {
    synchronized (mutex) {
        cleanUp();
    }
}
于 2010-02-16T20:44:44.170 に答える
0

このすべての混乱を明確にするには:

  1. リモート メソッドの実装を同期する場合、一度に実行できるクライアントは 1 つだけです。

  2. リモート オブジェクトでクリーナー タスクを同期すると、結合されます (1)。

  3. リモート メソッドを静的として定義することはできません。

于 2011-05-16T01:07:48.553 に答える
-1

RMI は「リモート オブジェクト」の錯覚を作成することに注意する必要がありますが、実際には、ローカル スタブ、リモート スケルトン、および実際のリモート オブジェクトの 3 つ以上のオブジェクトがあります。設計上のトレードオフとして、この錯覚は完全ではなくローカルスタブのみをロックしています。ネットワーク全体での同期はありません。インターネットで RMI+stub+synchronized を検索すると、次のような多くの説明が見つかります。

Java RMI と同期メソッド

したがって、ある種の非 RMI の、純粋にサーバー側の同期を自分で実装する必要があります。次に、この純粋なサーバー側ロックをリモート メソッドから呼び出すことができます。ただし、追加レベルの間接化が必要です。

コードをテストする最も簡単な方法は、Eclipse のような優れたデバッガーでスレッドを一時停止することです。Eclipse は、一時停止中のどのスレッドがどのロックを保持しており、他のどのスレッドをブロックしているかを明確に示します。

于 2010-11-13T11:29:42.667 に答える