2011-10-08 5 views
0

のスレッドを作成し、それぞれ、サーバに、ObjectOutputStreamを使用してシリアル化オブジェクトを送信します。クライアント/サーバソケットプログラムで2つのスレッドをリンクする - Java

サーバー

Bがそれを引き起こし共有リソースミューテックスに同期メソッドを呼び出します(新しいクライアントが接続するたびに)各ソケット接続のための新しいスレッドBを作成します(B)〜wait() Mutexの内部条件が真となるまで。 Bが現在待機していることを知ることができますどのようにこの場合

この説明は明確です。

クラス編曲:

A1--------->B1-------->|  | 
A2--------->B2-------->| Mutex | 
A3--------->B3-------->|  | 

EDIT: それは(待機を持っている必須です)、notify()あるいはnotifyAll()、これは同時実行がテストされている学術プロジェクトのためにあるからです。

+0

なぜ知っておく必要がありますか?Bは長期間ブロックされますか?そうであれば、そのアプローチはまったく縮尺されません... –

+0

なぜ、AはBが待っていることを知る必要がありますか? – MasterCassim

+0

Bが現在待機中であることを知る必要があるのは何ですか?シリアル化されたオブジェクトを送信した後、Bが応答を返すのを待たずに –

答えて

4

通常、Aはソケットによって読み取られます。これは、Bによって何らかのデータが返送されるまで「ブロック」されます(つまり、戻されず、ハングアップしません)。Bの待機状態を処理するために書き込む必要はありませんそれは読んでいるだけで、本質的に何かを待つことを含む。

更新これで、Aのユーザーインターフェイスの応答を維持します。これを行う最良の方法は、ユーザーインターフェイスライブラリのイベントキューシステムを利用することです。すべてのGUIフレームワークには、イベントをハンドラに送る中央イベントループがあります(ボタンクリック、マウス移動、タイマーなど)。通常、バックグラウンドスレッドがそのイベントキューに何かをポストしてメインで実行される方法がありますUIスレッド。詳細は使用しているフレームワークによって異なります。

例えば、Swingで、バックグラウンドスレッドはこれを行うことができますが:

SwingUtilities.invokeAndWait(someRunnableObject); 

ですから、このインタフェースを定義するとします。

public interface ServerReplyHandler { 
    void handleReply(Object reply); 
} 

続いたときに使用するようにGUIコードの素敵なAPIを作りますサーバーに要求を送信したい:

public class Communications { 

    public static void callServer(Object inputs, ServerReplyHandler handler); 

} 

したがって、クライアントコードは次のようにサーバーを呼び出すことができます。

showWaitMessage(); 

Communications.callServer(myInputs, new ServerReplyHandler() { 
    public void handleReply(Object myOutputs) { 

     hideWaitMessage(); 
     // do something with myOutputs... 

    } 
}); 
は、上記のAPIを実装するには、 inputsオブジェクトと各要求のハンドラを保存する要求オブジェクトのスレッドセーフなキューを持っていると思います。そして、ちょうどサーバにシリアル化された入力を送って、キューからの要求を引くが、何もしないバックグラウンドスレッドは、応答をリードバックし、それをdeserialiseし、この操作を行います。バックグラウンドスレッドとしてのでお早め

final ServerReplyHandler currentHandler = ... 
final Object currentReply = ... 

SwingUtilities.invokeAndWait(new Runnable() { 
    public void run() { 

     currentHandler.handleReply(currentReply); 

    } 
}); 

を返信を読み返した後、それをコールバック経由でメインのUIスレッドに戻します。

これは、ブラウザがJSコードから非同期通信を行う方法とまったく同じです。あなたはjQueryのに精通している場合、上記のCommunications.callServer方法は同じパターンである。

showWaitMessage(); 

$.get('http://...', function(reply) { 

    hideWaitMessage(); 

    // do something with 'reply' 
}); 

この場合の唯一の違いは、あなたが手で全体の通信スタックを書いているということです。

アップデート2

あなたは尋ねた:

をあなたは私がCommunications.callServerで "myInputs" と "新しいObjectOutputStreamの()のwriteObject(OBJ)" を渡すことができます意味ですか?

すべての情報がシリアル化されたオブジェクトとして渡される場合は、callServerにシリアル化を構築できます。呼び出しコードは、シリアル化をサポートするオブジェクトを渡すだけです。 callServerの実装は、そのオブジェクトをbyte[]にシリアル化し、それを作業キューにポストします。バックグラウンドスレッドは、それをキューからポップし、バイトをサーバーに送信します。

これは、バックグラウンドスレッドでオブジェクトを直列化しないようにすることに注意してください。これの利点は、すべてのバックグラウンドスレッドのアクティビティがUIコードから分離されていることです。 UIコードは、通信のためにスレッドを使用していることを完全に知らないことがあります。

Re:waitnotifyなどです。これらを使用するために独自のコードを書く必要はありません。 BlockingQueueインターフェイスの標準実装のいずれかを使用します。この場合、デフォルトコンストラクタでLinkedBlockingQueueを使用すると、無制限の数の項目を受け入れることができます。つまり、キューに登録することは、常にブロックせずに実行されます。だから、:

private static class Request { 
    public byte[] send; 
    public ServerReplyHandler handler; 
}; 

private BlockingQueue<Request> requestQueue; 

public static callServer(Object inputs, ServerReplyHandler handler) { 

    ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); 
    new ObjectOutputStream(byteStream).writeObject(inputs); 

    Request r = new Request(); 
    r.send = byteStream.toByteArray(); 
    r.handler = handler; 
    requestQueue.put(r); 
} 

。一方、バックグラウンドワーカースレッドがこのやっている:

for (;;) { 
    Request r = requestQueue.take(); 

    if (r == shutdown) { 
     break; 
    } 

    // connect to server, send r.send bytes to it 
    // read back the response as a byte array: 

    byte[] response = ... 

    SwingUtilities.invokeAndWait(new Runnable() { 
     public void run() { 
      currentHandler.handleReply(
       new ObjectInputStream(
        new ByteArrayInputStream(response) 
       ).readObject() 
      ); 
     } 
    }); 
} 

shutdown変数だけである:すなわち、それは特別な信号として使用するダミーのリクエスト

private static Request shutdown = new Request(); 

です。これにより、別のパブリック静的メソッドを使用して、UIがバックグラウンドスレッドに終了を要求できるようにすることができます(shutdownを置く前にキューをクリアしている可能性があります)。

パターンの重要な点に注意してください.UIオブジェクトはバックグラウンドスレッドでは決してアクセスされません。 UIスレッドからのみ操作されます。所有権の明確な分離があります。データは、スレッド間でバイト配列として渡されます。

同時に複数の要求をサポートしたい場合は、複数のワーカーを起動することができます。

+0

+1。 Plsは私の上記のコメントを見ている。 – coder9

+0

私は別の+1を与えたでしょう。いつかこれを読んで、これが問題を解決するかどうかを知るためにいつかかかります。ユーザーがそのGUI上で何かをするのを防ぐために、待ち受けBにリンクされたAが必要です。私も前にEDTのものを試してみました、あなたは私の以前の投稿がすべてそれについて知ることができます:http://stackoverflow.com/questions/7696472/background-process-in-swingworker-causes-eventqueue-to-freeze-in-java-完全な-c – coder9

+0

メソッド "handleReply"とクラス "ServerReplyHandler"はどのように見えますか? – coder9