2012-04-26 7 views
1

私は、クラスがあるプロジェクト、DeviceCommunicator、そのimplements Runnableに取り組んでいます。現在、メインクラスは、Socketライブラリを使用して(最終的に)ローカルネットワーク上のデバイスに接続するDeviceCommunicatorという単一インスタンスをインスタンス化します。runnableを実装してソケットをオープンするクラスを複数回インスタンス化するにはどうすればいいですか?

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

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

EDIT:次のコード行を介してソケット明確にするために、プログラムが実行されると、これは操作の順序である:

1)MAINクラスのようなコンストラクタ/ wのDeviceCommunicatorクラスをインスタンス化します。

comm1 = DeviceCommunicator(hostName, portNum)

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

comm1.send(someString)

3)COMM1はタイプDeviceCommunicatorのものであり、ホスト名にSocket接続を開きます/ portNumのように:

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

4)COMM1が出力PrintStreamsomeStrを送信し、次のコードを使用して応答をリッスンするスレッドを初期化します

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

によりリスニングDeviceCommunicatorスレッドがコンストラクタの引数を持っていないという事実のために、それがいることを必要としました出力はPrintStream、入力はBufferedReaderstaticとなります。

DeviceCommunicatorのインスタンスが1つしかない場合、これは素晴らしい動作です!

しかし、私はその後、同じまたはローカルネットワーク上の別のデバイスのいずれかに接続することができDeviceCommunicatorクラスの複数のインスタンスを好きしかしDeviceCommunicatorクラスの出力と入力がstaticであるという事実を考慮しう彼らは共有されている(私は、のすべてのインスタンスにわたって静的な変数の変更が他の実行中のスレッドに見えることをJVMが保証していないと読んだことがあると思う - これは問題です!

私はいくつかの研究を行ってきたと私は非常に似てトピックに遭遇していない - ほとんどのトピックでは、基本的には「二者択一」です:

A)のトピックを、約ソケット通信を通され、ここで "非ブロッキング "通信は静的変数の使用によって達成される。他方は別の(典型的にはわずかに変更された)タスクを達成しながら、一つのスレッドは、一方(典型的には、単純な)タスクを達成する、請求

又は

B)単純implements Runnable場合を考えます。

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

私にはわからないこの問題に対する明らかな解決策がありますか?

ありがとうございます!

+1

あなたのクラスは 'DeviceCommunicator'ですか?ストリームに 'static'変数を使わなければならないのはなぜですか?私は新しいコンストラクタを追加できませんか? – Gray

+0

はい、 'DeviceCommunicator'は、' Main'クラスによってインスタンス化されるクラスです。私はストリームに 'static'変数を使用することを考えました(これはすでに説明されていると思っていましたので、教えてください)。 'Socket'接続を作成するときに設定されたメインの' DeviceCommunicator'と同じ入力 'BufferedReader'です。私は何かをクリアすることができるかどうかを確認するコードをいくつか追加します。 – MandM

+0

Javaは常に「値渡し」ですが、誤解を招くことです。引数が(キューのような)オブジェクトの場合、呼び出し元と呼び出し先の両方が同じオブジェクトへの参照を持ちます。すべてのキュー操作は、両方のスレッドから見えます。 – Gray

答えて

2

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

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

ここで、複数のスレッドがストリームを読み書きしている場合は、ストリームを同期させなければなりません。

また、あなたのコメントには、送信するメッセージのQueueが必要であると述べました。

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

しかし、より良いパターンにアイテムを追加しますDeviceCommunicatorsendメソッドを追加することです:あなたは、同期リストか何かすることを確認する必要がありますが、それはまた、DeviceCommunicatorの引数かもしれませんメインスレッドと送信スレッドの両方ではなく、キューと同じキューを持つ。 DeviceCommunicatorにメソッドを追加すると、リーダーとライターのストリームも隠すことができ、メインスレッドはストリームに直接アクセスしません。 Data hidingは、オブジェクト指向プログラムの重要な機能の1つです。

+0

です。エラー戦略にはいくつか考慮すべきである。これはスレッドとのやり取りのための「TheadComms」クラスのためのものです。バッファされたデータだけでなく、エラーメッセージや例外オブジェクトなども保持できます。 'OnDataRx'や 'OnError'のようなイベントで何かを起動させる場合、それはストリームインスタンスではありません:) –

+0

良い点@Martinしかし、なぜその機能を 'DC'クラスに追加しないのですか?それとも、あなたのスレッドリターンのすべてに使用するクラスがありますか?そこで、 '新しいThreadComm ()'を作成し、 'Future'-ish機能を持つ' DC'コンストラクタに渡します。それは素晴らしいパターンになるはずです。 – Gray

+0

申し訳ありませんが、私は過去数日間離れていましたが、詳細な答えに感謝します!しかし、私は質問があります - あなたは 'キューに項目を追加する' 'DC'クラスに' send'メソッドを追加することに言及しています。この場合、メインクラスとリスナークラスの両方に同じキューがありませんか?私が今まで実行してきた方法は、おそらく最適な解決策ではないようです。私の主な 'DC'クラスは、実際にソケットを通してメッセージを送信し、応答を処理するためにリスナー' DC'クラスをインスタンス化するものです私が聞いていると思うのは、リスナーに聞かせてもらわない理由です。 – MandM

関連する問題