2012-10-10 9 views
8

サブクラスThreadにプライベートSelectorと公開register(SelectableChannel channel, ...)メソッドがあり、他のスレッドがチャンネルをセレクタに登録できるようにしています。NIOセレクタ:選択時に新しいチャンネルを正しく登録する方法

としては中にhere、チャネルのregister()ブロックに答えセレクタのselect()/select(long timeout)ので、我々は、セレクタをwakeup()する必要があります。

スレッドが中断しない限り無期限に選択し、チャネルのregister()が呼び出される前に実際に次の選択に入ることを管理します。だから私は​​ブロックで単純なロックを使用してregister()が確実に最初に起こることを確認しました。

コード:(読みやすくするために除去無関係コード)

public class SelectorThread extends Thread { 
    ... 

    public void register(SelectableChannel channel, Attachment attachment) throws IOException { 
    channel.configureBlocking(false); 
    synchronized (this) { // LOCKING OCCURS HERE 
     selector.wakeup(); 
     channel.register(selector, 
         SelectionKey.OP_READ, 
         attachment); 
    } 
    } 

    @Override 
    public void run() { 
    int ready; 
    Set<SelectionKey> readyKeys; 
    while (!isInterrupted()) { 
     synchronized (this) {} // LOCKING OCCURS HERE 

     try { 
     ready = selector.select(5000); 
     } catch (IOException e) { 
     e.printStackTrace(); 
     continue; 
     } 

     if (ready == 0) { 
     continue; 
     } 

     readyKeys = selector.selectedKeys(); 

     for (SelectionKey key : readyKeys) { 
     readyKeys.remove(key); 

     if (!key.isValid()) { 
      continue; 
     } 

     if (key.isReadable()) { 
      ... 
     } 
     } 
    } 
    } 
} 

この単純なロックは、スレッドが次に選択ループを続行する前register()が起こることを可能にします。私がテストした限り、これは想定どおりに動作します。

質問: これは「良い」方法ですか、それとも深刻な欠点がありますか?登録のためのチャンネルやthisのようなもっと洗練されたロックを格納するために、リストやキュー(推奨のhere)を使用する方が良いでしょうか?それの長所/短所は何ですか?それとも「もっと良い」方法がありますか?

+0

select()が呼び出されているときにセレクタにチャネルを登録しているときに[Javaスレッドブロックの重複が可能です。どうすればいいですか?](https://stackoverflow.com/questions/1057224/java-thread-blocks-while-registering-channel-with-selector-while-select-is-cal) – Flow

答えて

3

私は実際には、空のブロックがコンパイル時に削除されないロック取得に驚いています。かなりうまく動作します。私はそれが働くことを意味します、それは先制的です、それは最も良いアプローチではありませんが、それは動作します。それは予測可能なので睡眠より優れています。ウェイクアップコールを使用しているので、選択タイムアウトに純粋に頼っていた場合は、定期的な更新ではなく、必要に応じて進捗状況が確認されます。

このアプローチの主な欠点は、リクエストを処理する場合でも、何か他のものを登録するよう呼び出すことです。これはあなたのシステムには当てはまるかもしれませんが、通常はそうではありませんが、これは可能な問題です。もっと前向きな思考である小さな問題は、この場合、より大きなオブジェクトの一種であるSelectorThread自体をロックすることです。あなたが拡大するにつれて悪くないですが、このロックは他のクライアントがこのクラスを使用するたびに文書化して考慮する必要があります。個人的には、予期せぬ未来の危険を避けるために、別のロックを全部作っていくつもりです。

個人的には、私はキューイング技術が好きです。彼らはあなたのスレッドに、マスターやワーカーのようにロールを割り当てます。キューからのより多くの登録のためのすべての選択チェックの後、すべてのタイプのコントロールがマスターで起こるのに対し、読み取りタスクをクリアしてファームウェアを出し、全体の接続設定の変更を処理します(切断など)... "bs"モデルはこのモデルをかなりうまく受け入れているようで、それはかなり標準的なモデルです。私はそれが悪いことだとは思わない、コードを少しハック、テスト、およびより簡単に読むことができます。書き出すのにちょっと時間がかかります。

私は最後にこの記事を書いて以来、長い時間を過ごしています。そこには他のライブラリがあり、あなたのためのキューイングを世話しています。

Grizzly Nio Framework少し古いながら、私はそれを使用した最後の時間、メインrunloopは悪くありませんでした。それはあなたのために多くのキューイングをセットアップします。

Apache Mina同様に、キューイングフレームワークを提供します。

しかし、私は最終的にそれがあなたが取り組んでいるものによって異なることを意味します。

  • フレームワークで遊ぶのは単なる1人のプロジェクトですか?
  • 何年も生き続けたい制作コードですか?
  • これは反復処理しているプロダクションコードですか?

あなたが顧客に提供しているサービスの中核としてこれを使用する予定がない限り、あなたのアプローチはうまくいきます。長期的にはメンテナンスの問題があるかもしれません。

+0

私にとって非常に良い入力、ありがとう。ウェイクアップは待機中の選択にのみ影響し、ループの残りの部分には影響しないので、レジスタトランプはサービスするとは思わない。ロックについては、代わりに単純なプライベートオブジェクトをロックする方がよいでしょうか? (レジスタ呼び出しをロックするためのオブジェクト)大量のチャネルを同時に登録することは期待できないので、レジスタキューは多すぎると思います。しかし私はそのアイデアが気に入っていて、将来それを実装するかもしれません。 – riha

+0

RE:選択して修理する、そうです、それは私が意味することです。ちょうど起こった登録に対処するために空のサイクルを過ごすように。恐ろしいことではありませんが、余分なロックが必要ですぐに対処します。キューイングシステムでは、通常、非ロックキューがあり、これらのロックの必要性を高めます。 –

+0

RE:ロック、ええ、私は個人的にセレクタを扱うための内部ロックを作ります。しかし、ええ、それはあなたが良い行くように聞こえる。 –

4

セレクタなどをスレッドセーフではないとして処理すると、Darronが示唆したように、すべてのスレッドを同じスレッドで選択して実行してください。

NIOセレクタの同時実行モデルはであり、くそです。私はそれを呼び出す必要があります。なぜなら、それを勉強しようとする人にとっては時間の無駄です。結論として、結論は、それを忘れることです。同時使用ではありません。

2

register()の前にwakeup()が必要で、selectループでは、ready()が0の場合は短いsleepを実行してregister()を実行するだけです。追加の同期はありません:既に十分に悪いです。それを悪化させないでください。私は登録、キャンセル、関心事変更などのこれらのキューのファンではありません:彼らは単に実際に並行して行うことができるものを逐次化します。

+0

登録の仕方を詳しく教えてくださいチャンネルは本当に並行して行うことができますか?登録が同じスレッドでのみ実行できるのであれば、それはどのように並行することができますか?また、「短い睡眠」とは何でしょうか? 1ms? 10ms? 100ms? – riha

+1

@rihaえ?私はチャネルの登録はselect()スレッドでのみ行うことができると言っていません。これは、正確にそのトピックに関するあなたの質問に答えて、私がここで説明したテクニックを使って別のスレッドで行うことができます。確かにそれは明らかですか?睡眠は100msで十分でしょう。 – EJP

+0

ああ、私はそれを読む[ここ](http://stackoverflow.com/a/2179612/589008)、申し訳ありません。しかし、複数のチャンネルを「同時に」登録する際に、セレクタによって施されたロックに踏み込んでいるわけではありませんか?その場合、キューを使用する利点はどこにありますか? – riha

関連する問題