2012-06-20 65 views
2

我一直在嘗試將NIO與多線程讀取處理進行配對,以便構建一個可伸縮的服務器。我不能使用Netty或MINA等任何框架,因爲有幾個低級別的客戶端 - 服務器協議細節,這些細節在實現時都會花費太多精力。我只是檢查我的代碼,我意識到有這個片段潛在的競爭條件:用於異步服務器的Java NIO和多線程

//executes in selector thread 
public void runSelector() { 
    //... 
    Set<SelectionKey> keys = selector.selectedKeys(); 
    for (Iterator<SelectionKey> keyIter = keys.iterator(); keyIter.hasNext();) { 
     final SelectionKey key = keyIter.next(); 
     keyIter.remove(); 
     if (key.isValid() && key.isReadable()) { //point A 
      //maybe some other short calculations 
      ((SocketChannel) key.channel()).read(buffer); //point B 
      workerThreadPool.submit(new Runnable() { public void run() { processRead(key, buffer); } }); 
     } 
    } 
    //... 
} 

//executes in a worker thread 
private void processRead(SelectionKey key, ByteBuffer buf) { 
    //... somewhere 
    key.cancel(); 
    //... 
} 

這是極不可能的事件,但它是完全有可能的是在一個工作線程,我打電話key.cancel( )而選擇器線程位於我在runSelector()方法中評論的兩個點之間。請記住,這可以部署在高併發機器上,並且運行選擇器線程的CPU內核可能會陷入困境。 key.cancel()是否可以在選擇器線程中的key.isReadable()和channel.read()之間的工作線程中調用並導致CancelledKeyException?我是否應該有某種線程安全的集合來存儲所有要取消的鍵,以便runSelector()可以在迭代結束時取消所有這些鍵? Netty或MINA等更專業的項目如何處理這種情況?

回答

1

鎖定資源,

synchronized(key) { 
    ((SocketChannel) key.channel()).read(buffer); //point B 
} 

如果着眼於對併發this甲骨文教程奇怪的樣子。

+0

哇,我不敢相信我沒有想到同步。我想其中一個解決方案是將key.cancel()與synchronized同步並將key.isValid()&& key.isReadable()與同步的塊封裝在一起。非常感謝! –