4

私は java.nio.channels.Selector を使用しており、読み取り/書き込み/受け入れの準備ができている selectedKey ごとに個別のスレッドを作成したいのですが、同じソケットが 2 つの異なるによって処理されないようにしたいと考えています。同時にスレッドします。それを行う最良の方法は何ですか?ソケットを処理するスレッドを作成し、スレッドが寿命を迎えたらソケットをセレクターに再登録する前に、各 selectedKey をキャンセルすることを考えていましたが、これがどれほど効率的かはわかりません....

4

2 に答える 2

9

Java でのスケーラブル I/O に関する非常に優れた Doug Leaプレゼンテーションがあり、サーバーを構築するときにそれに従いました。私は次のアプローチを取ります。

「リアクター」内に、I/O (および非常に基本的なデコード/エンコード)のみを実行する単一の I/O スレッドがあります。単純にバイトとメッセージ オブジェクトを変換し、着信メッセージ オブジェクトをビジネス ロジック処理用のスレッド プールに渡します。このアプローチを強くお勧めします-I/O スレッドが飽和しない限り、複数の I/O スレッドは必要ありません。ほとんどの I/O ボトルネックは、このスレッドで他の処理が行われているためだと思います。

I/O スレッドが飽和していることを証明できる場合は、プレゼンテーションで提案されている「複数のリアクター」パターンに従うことができます。これにより、マスター リアクターは着信接続を受け入れ、処理を実行する子リアクターにそれらを渡します。各子リアクターは、接続全体のサブセット間で多重化されるため、複数のスレッドが特定の と相互作用する危険はありませんSelectionKey

于 2010-01-08T12:41:33.177 に答える
1

ソケットごとに個別のスレッドを作成すると、多すぎる可能性があると思います。また、新しいThreadものを作成すると、実行時間が長くなります。スレッド プールを使用して、アクティブなスレッドの数を制限し、新しいスレッドの作成を制限する必要があります。java.util.concurrent.Executors固定スレッド プールを作成する機能を提供します。詳細はhttp://java.sun.com/docs/books/tutorial/essential/concurrency/pools.htmlを参照してください。

一度に複数のスレッドにヒットしないように保護したいソケットの場合は、最も単純な除外を検討します: ソケット オブジェクトをロックします。より効率的な戦略があるかもしれませんが、おそらくこれほど単純で確実なものはありません。

アップデート

以前に返されたソケットの一部がまだ処理中である間に別の選択が行われると、スレッドが互いに干渉することになる可能性があります。ロックを介して他のスレッドをシャットアウトすることは可能ですが、実際にはエレガントな解決策ではありません (申し訳ありません)。

私が考えることができる2つの選択肢:

  • 処理スレッドを開始する前にチャネルの登録を解除し、処理アクティビティの最後に再登録します。不器用に聞こえますが、仕事を終わらせる必要があります。

  • などの進行中のチャネルの独自のデータ構造を維持Setし、スレッドに渡す前にそのセットに新しく見つかった準備ができたチャネルを追加し、スレッドから戻る前にそれを削除します。選択セットからチャネルを処理する場合、既にセット内にあるものはすべて無視します。このセットの使用はすべて同期する必要があります。

于 2010-01-08T12:19:00.270 に答える