我的Java NIO選擇使用select()所以塊來實現,直到任何這些發生:爪哇NIO選擇器選擇()返回0儘管通道是準備
- 註冊通道準備
- 它是wakeup()' ED
- 線程被中斷
由此,我對於該情況下的幾個假設,其中select()
返回0:
- 它一定是原因2或3
- selectedKeys()應該返回一個空
ResultSet
- 我並不需要調用
selectedKeys()
並可以繼續下一個循環迭代,其中select()
將被調用再
但是,我遇到的情況下select()
返回0雖然有一個就緒通道。按照預期,selectedKeys()
返回Set
,1 SelectionKey
。
即使幾次調用select()
也會一直返回0,直到通道被處理並且SelectionKey
被移除。這種情況在一個無限循環爲select()
不會阻止基本上結束了,但總是立即返回0
簡化代碼:
Selector selector = Selector.open();
SocketChannel channel;
for (...) { // for each node
// Create and connect channels...
...
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ, someRelatedObject);
}
int ready;
Set<SelectionKey> readyKeys;
while (true) {
ready = selector.select();
readyKeys = selector.selectedKeys();
System.out.println("Ready channels: " + ready);
System.out.println("Selected channels: " + readyKeys.size());
if (ready == 0) {
continue;
}
for (SelectionKey key : readyKeys) {
if (key.isValid() && key.isReadable()) {
// Take action...
}
readyKeys.remove(key);
}
}
爲什麼select()
返回0雖然有現成的渠道呢? 建議如何處理這個問題?
編輯:
更改此:
for (SelectionKey key : readyKeys) {
if (key.isValid() && key.isReadable()) {
// Take action...
}
readyKeys.remove(key);
}
這個
for (SelectionKey key : readyKeys) {
readyKeys.remove(key);
if (key.isValid() && key.isReadable()) {
// Take action...
}
}
解決了這個問題。在某些情況下,代碼將在remove()
之前循環continue
for
。
編輯2:
我剛剛得知我的foreach循環超過設定的選擇鍵是壞的。 foreach使用集合的迭代器。迭代時直接修改集合(不通過迭代器的方法)可能會導致「任意的,不確定的」行爲。
所選鍵集可能會提供快速失敗迭代器。 快速失敗迭代器檢測到這種修改,並在下一次迭代時拋出ConcurrentModificationException。因此,修改foreach中的集合可能會導致不確定的行爲,或者可能導致異常 - 這取決於迭代器的實現。
解決方案:不要使用foreach。使用迭代器並通過iterator.remove()刪除密鑰。
Iterator<SelectionKey> iterator;
SelectionKey key;
while (true) {
// ...
iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
key = iterator.next();
iterator.remove();
// ...
}
}
可能是否一個密鑰準備好,並沒有被刪除? – riha 2012-03-30 09:17:37