通常、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:wait
とnotify
などです。これらを使用するために独自のコードを書く必要はありません。 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スレッドからのみ操作されます。所有権の明確な分離があります。データは、スレッド間でバイト配列として渡されます。
同時に複数の要求をサポートしたい場合は、複数のワーカーを起動することができます。
なぜ知っておく必要がありますか?Bは長期間ブロックされますか?そうであれば、そのアプローチはまったく縮尺されません... –
なぜ、AはBが待っていることを知る必要がありますか? – MasterCassim
Bが現在待機中であることを知る必要があるのは何ですか?シリアル化されたオブジェクトを送信した後、Bが応答を返すのを待たずに –