在我目前的項目中,我注意到select()
未按預期阻塞。 即使沒有IO存在,它也不會阻止並始終返回。所以我得到了一個繁忙的CPU。Selector.select不按預期方式阻止
註冊將始終由另一個線程調用,所以我需要鎖定和喚醒。
的醫生說爲selectNow()
:
調用此方法清除喚醒方法的任何先前調用的效果。
所以我在每次迭代結束時調用該方法。沒有succsess。 我沒有找到任何例子或解釋如何使用selectNow
爲我的目的。
代碼有什麼問題?
這是我的示例代碼,所以你可以測試這個。
BTW:另一個stackoverflow問題是我的代碼的rolemodel。 編輯:修正示例!它現在有效。
import java.io.IOException;
import java.net.*;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.concurrent.locks.ReentrantLock;
public class Test implements Runnable {
ReentrantLock selectorLock = new ReentrantLock();
Selector selector;
boolean alive;
@Override
public void run() {
SelectionKey key;
Iterator<SelectionKey> keys;
alive = true;
try {
while (alive) {
selectorLock.lock();
selectorLock.unlock();
selector.select();
System.out.println("select() returned");
keys = selector.selectedKeys().iterator();
// handle each "event"
while (keys.hasNext()) {
key = keys.next();
// mark as handled
keys.remove();
// handle
handleKey(key);
}
//selector.selectNow(); // don't fix this
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void handleKey(SelectionKey key)
throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
if (key.isConnectable()) {
System.out.println("connecting");
if (channel.finishConnect()) {
key.interestOps(SelectionKey.OP_READ);
} else {
key.cancel();
}
} else if (key.isReadable()) {
System.out.println("reading");
// read and detect remote close
channel.read(ByteBuffer.allocate(64));
}
}
public void register(SelectableChannel channel, int ops, Object attachment)
throws ClosedChannelException {
selectorLock.lock();
try {
System.out.println("wakeup");
selector.wakeup();
channel.register(selector, ops, attachment);
} finally {
selectorLock.unlock();
}
}
public Test()
throws IOException {
selector = Selector.open();
}
public static void main(String[] args)
throws IOException {
Test t = new Test();
new Thread(t).start();
SocketAddress address = new InetSocketAddress("localhost", 8080);
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(address);
t.register(channel, SelectionKey.OP_CONNECT, "test channel attachment");
}
}
謝謝。你的提示解決了這個問題。 我改變'handleKey'。 –
+1非常重要的建議,從文檔中丟失。 –