2017-03-03 2 views
0

メインスレッドがSelectorSelectionKeysを使用して多数の接続を処理するアプリケーションを作成しています。私は、タスクをワーカースレッドに渡そうとするときに、競合状態で何らかの問題に遭遇しました。SelectorとSelectionKeysを使用してスレッドプールに委任する

私のメインループは次のようになります。

selector = Selector.open(); //Create selector 

    serverSocketChannel = ServerSocketChannel.open(); //Create socket channel, configure blocking, and bind 
    serverSocketChannel.configureBlocking(false); 
    serverSocketChannel.bind(new InetSocketAddress(PORT)); 

    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //Register channel to selector 

    ByteBuffer buffer = ByteBuffer.allocate(8000); 

    while(true){ 
     selector.select(); 

     Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); 

     while(iterator.hasNext()){ 
      SelectionKey key = iterator.next(); 

      if(key.isAcceptable()){ 
       SocketChannel socketChannel = serverSocketChannel.accept(); 
       socketChannel.configureBlocking(false); 
       socketChannel.register(selector, SelectionKey.OP_READ); 
      } 
      if(key.isReadable()){ 
       taskList.add(new ReadTask(key)); 
      } 
      if(key.isWritable()){ 

      } 

      iterator.remove(); 
     } 
    } 

ここでの考え方は、クライアントがサーバーにデータを送信しようとすると、それはOP_READの関心を持つキーを受信し、そのキーでタスクを作成することですので、スレッドプールはメインスレッドをブロックしないように読み込みを処理できます。

問題このループを呼び出すと、ワーカースレッドに渡されるキーの処理中に継続され、taskList.add(new ReadTask(key));が呼び出され、最終的​​が呼び出されたときの間の全体の時間は、メインスレッドがまだ反復されると見ているということですキーはまだ選択されています。キーのチャネル上で読み込みが呼び出された後、キーは非アクティブとしてマークされ、クライアントからの別の正当な書き込みによってキーが再度アクティブ化されるまでセレクタによって選択されないように見えます。

キーをマークして、セレクタが選択したキーのリストに読み込みを行わずに戻さないようにする方法はありますか?私はselector.selectedKeys.remove(key)を試しましたが、これはConcurrentModification例外を生成します。

答えて

0

選択ループで読み取りを行い、データを処理して応答を準備するか、応答が送信されるまで選択キーのinterestOpsからOP_READを削除する必要があります。

+0

ワーカースレッドはすでに開始されています。これらのタスクは同期キューを介して渡されます。あなたが推奨しているのは、OP_READを別のOP(OP_WRITEなど)に変更することです。 – 0x6

関連する問題