我有一个最小的JMS提供程序,它通过UDP发送主题消息并通过TCP发送队列消息.
我使用单个选择器来处理UDP和TCP选择键(注册SocketChannels和DatagramChannels).
我的问题是:如果我只发送和接收UDP数据包,一切顺利,但一旦我开始在TCP套接字上写(使用Selector.wakeup()让选择器进行实际写入),选择器进入无限循环,返回一个空的选择键集,并吃掉100%的CPU.
主循环的代码(稍微简化)是:
public void run() {
while (!isInterrupted()) {
try {
selector.select();
} catch (final IOException ex) {
break;
}
final Iterator<SelectionKey> selKeys = selector.selectedKeys().iterator();
while (selKeys.hasNext()) {
final SelectionKey key = selKeys.next();
selKeys.remove();
if (key.isValid()) {
if (key.isReadable()) {
this.read(key);
}
if (key.isConnectable()) {
this.connect(key);
}
if (key.isAcceptable()) {
this.accept(key);
}
if (key.isWritable()) {
this.write(key);
key.cancel();
}
}
}
synchronized(waitingToWrite) {
for (final SelectableChannel channel: waitingToWrite) {
try {
channel.register(selector, SelectionKey.OP_WRITE);
} catch (ClosedChannelException ex) {
// TODO: reopen
}
}
waitingToWrite.clear();
}
}
}
而对于UDP发送(TCP发送类似):
public void udpSend(final String xmlString) throws IOException {
synchronized(outbox) {
outbox.add(xmlString);
}
synchronized(waitingToWrite) {
waitingToWrite.add(dataOutChannel);
}
selector.wakeup();
}
那么,这里有什么问题?我应该使用2个不同的选择器来处理UDP和TCP数据包吗?
解决方法:
我建议你检查select()方法的返回值.
try {
if(selector.select() == 0) continue;
} catch (final IOException ex) {
break;
}
您是否尝试调试以查看循环的位置?
编辑:
>我建议不要在迭代器上调用“remove()”,而是在迭代它们之后调用selectedKeys.clear().迭代器的实现可能不会从底层集中删除它.
>检查您是否在连接的通道上注册OP_CONNECT.