2017-03-03 50 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 Exception。

回答

0

您應該在select循環中執行讀取操作,然後啓動worker以處理數據並準備響應,或者從選擇鍵的interestOps中刪除OP_READ,直到發送響應。

+0

工作線程已經啓動,這些任務通過同步隊列傳入。你推薦的是,我改變OP_READ到一個不同的OP(如OP_WRITE?),直到讀取發生? – 0x6