1

私は、クラスがあるプロジェクトに取り組んでDeviceCommunicatorimplements Runnableます。DeviceCommunicator現在、メイン クラスは、(最終的に) ライブラリを使用してローカル ネットワーク上のデバイスに接続する単一のインスタンスをインスタンス化しSocketます。

最終的には、メッセージを送信する必要がある場合、のインスタンスがDeviceCommunicatorデバイスへのソケット接続を開き、メッセージを送信してから、新しいスレッドを開始して、次の行を介してソケットからデータを受信することを意味しますコード:

new Thread(new DeviceCommunicator()).start();

編集:明確にするために、これはプログラムが実行されたときの操作の順序です:

1) class は、次のようなコンストラクターをMAIN使用してクラスをインスタンス化します。DeviceCommunicator

comm1 = DeviceCommunicator(hostName, portNum)

2)MAINクラスは にメッセージを送信したいので、次comm1のように呼び出しますsend

comm1.send(someString)

3) comm1 はタイプであり、次のような hostName/portNum へDeviceCommunicatorの接続を開きます。Socket

deviceSocket = new Socket(hostName, portNum);
out = new PrintStream(deviceSocket.getOutputStream());
in = new BufferedReader(new InputStreamReader(deviceSocket.getInputStream()));

4) comm1someStrは出力PrintStreamに送信し、次のコードでスレッドを初期化して応答をリッスンします。

new Thread(new DeviceCommunicator()).start();

リスニングスレッドにはコンストラクター引数がないため、出力変数と入力変数DeviceCommunicatorを作成する必要がありました。PrintStreamBufferedReader static

のインスタンスが 1 つしかない場合、DeviceCommunicatorこれはうまく機能します。

ただし、ローカルDeviceCommunicatorネットワーク上の同じデバイスまたは異なるデバイスに接続できるクラスの複数のインスタンスが必要ですが、クラスの出力と入力が共有されているという事実を考慮すると (私は思う、私はJVM は、静的変数の変更が他の実行中のスレッドから見えるようになることを完全に保証していないことを読みました) - これは問題です!DeviceCommunicatorstaticDeviceCommunicator

私はいくつかの調査を行いましたが、まったく同様のトピックに出くわしていません-ほとんどのトピックは基本的に「どちらかまたは」です。

A) トピックはスレッド化されたソケット通信に関するもので、静的変数を使用することで「ノンブロッキング」通信が実現されます。

また

B) implements Runnable1 つのスレッドが 1 つの (通常は単純な) タスクを実行し、もう 1 つのスレッドが別の (通常はわずかに変更された) タスクを実行する単純なケースを考えます。

編集:提案される可能性のある解決策の1つは、単に入力BufferedReaderをリッスンDeviceCommunicatorスレッドに渡すことだと思いますが、送信されるメッセージのキューを実装しています(ネットワークに問題がある場合); そのため、メッセージを送信する必要がある場合は、キューの最初の要素を取得してソケット接続に出力し、リッスン スレッドで、メッセージがデバイスによって正しく受信されたことを確認したいと考えています。メッセージが正しく受信された場合は、キューから要素を削除したいと思いますが、これも問題を引き起こします.Javaでの変数の受け渡しは、参照ではなく常に値です! BufferedReader したがって、入力とキューを渡すとしたら、リスニングで変更されていたキューDeviceCommunicatorDeviceCommunicatorメインインスタンスで変更する必要がある実際のキューではありません。

私が気付いていないこの問題の明白な解決策はありますか?

前もって感謝します!

4

1 に答える 1

2

クラスを制御できる場合は、必要なまたはオブジェクトを引数としてコンストラクターにDeviceCommunicator渡します。私は確かにそのように変数を使用しません。StreamReaderstatic

new Thread(new DeviceCommunicator(hostName, portNum, in, out)).start();

ここで、複数のスレッドがストリームを読み書きしている場合は、それを行う前にそれらを同期する必要があります。

Queueまた、コメントで、送信するメッセージの数が必要であると述べました。これも引数になる可能性がありDeviceCommunicatorますが、それを同期リストなどにする必要があります。

List<String> toSendList = Collections.synchronizedList(new ArrayList<String>());
...
new Thread(new DeviceCommunicator(hostName, portNum, in, out, toSendList)).start();

ただし、より良いパターンは、同じキューを持つメイン スレッドと送信スレッドの両方ではなく、項目をキューに追加するsendメソッドをに追加することです。DeviceCommunicatorにメソッドを追加するとDeviceCommunicator、リーダー ストリームとライター ストリームも非表示にすることができ、メイン スレッドはストリームに直接アクセスしなくなります。 データ隠蔽は、オブジェクト指向プログラムの重要な機能の 1 つです。

于 2012-04-26T17:08:10.147 に答える