Java 选择器。选择“不按预期阻止”

Java 选择器。选择“不按预期阻止”,java,multithreading,locking,nio,Java,Multithreading,Locking,Nio,在我当前的项目中,我注意到select()没有按预期阻塞。 即使没有IO,它也不会阻塞并始终返回。所以我的cpu很忙 注册总是由另一个线程调用,所以我需要锁和唤醒 文档上说对于selectNow(): 调用此方法将清除以前调用唤醒方法的任何效果 因此,我在每次迭代结束时调用该方法。没有成功。 我没有找到关于如何使用selectNow的示例或说明 代码有什么问题 这是我的示例代码,您可以对其进行测试 顺便说一句:另一个stackoverflow问题是我代码的角色模型。 编辑:示例已修复!现在可以

在我当前的项目中,我注意到
select()
没有按预期阻塞。 即使没有IO,它也不会阻塞并始终返回。所以我的cpu很忙

注册总是由另一个线程调用,所以我需要锁和唤醒

文档上说对于
selectNow()

调用此方法将清除以前调用唤醒方法的任何效果

因此,我在每次迭代结束时调用该方法。没有成功。 我没有找到关于如何使用
selectNow
的示例或说明

代码有什么问题


这是我的示例代码,您可以对其进行测试

顺便说一句:另一个stackoverflow问题是我代码的角色模型。 编辑:示例已修复!现在可以了

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");
    }
}
import java.io.IOException;
导入java.net。*;
导入java.nio.channels.*;
导入java.util.Iterator;
导入java.util.concurrent.locks.ReentrantLock;
公共类测试实现可运行{
ReentrantLock selectorLock=新的ReentrantLock();
选择器;
布尔活着;
@凌驾
公开募捐{
选择键;
迭代器键;
活着=真;
试一试{
(活着时){
选择lock.lock();
选择lock.unlock();
selector.select();
System.out.println(“select()返回”);
keys=selector.selectedKeys().iterator();
//处理每个“事件”
while(keys.hasNext()){
key=keys.next();
//标记为已处理
键。移除();
//处理
手钥匙;
}
//selector.selectNow();//不要修复此问题
}
}捕获(IOE异常){
e、 printStackTrace();
}
}
私有无效handleKey(SelectionKey)
抛出IOException{
SocketChannel=(SocketChannel)key.channel();
if(key.isConnectable()){
System.out.println(“连接”);
if(channel.finishConnect()){
key.interesttops(选择key.OP_READ);
}否则{
键。取消();
}
}else if(key.isReadable()){
系统输出打印项次(“读取”);
//读取并检测远程关闭
channel.read(ByteBuffer.allocate(64));
}
}
公共无效寄存器(SelectableChannel、int ops、对象附件)
抛出ClosedChannel异常{
选择lock.lock();
试一试{
System.out.println(“唤醒”);
selector.wakeup();
通道寄存器(选择器、ops、附件);
}最后{
选择lock.unlock();
}
}
公开考试()
抛出IOException{
选择器=selector.open();
}
公共静态void main(字符串[]args)
抛出IOException{
测试t=新测试();
新线程(t.start();
SocketAddress地址=新的InetSocketAddress(“本地主机”,8080);
SocketChannel通道=SocketChannel.open();
信道配置阻塞(假);
通道连接(地址);
t、 寄存器(通道,SelectionKey.OP_CONNECT,“测试通道附件”);
}
}

在启动
OP\u CONNECT
并且
finishConnect()
返回“true”之前,不要注册
OP\u READ
。此时,您必须取消注册
OP\u CONNECT

类似地,在有东西要写之前,不要注册OP_WRITE的通道<除非套接字发送缓冲区已满,否则code>OP_WRITE始终处于就绪状态,因此只有在检测到该条件(
WRITE()
返回零)后,才应注册该条件,并且应立即取消注册该条件(除非该条件再次发生)


最后,
OP\u CONNECT
OP\u WRITE
在引擎盖下是一样的,这就是我刚才所说的
OP\u WRITE
解释了选择器旋转的原因。

谢谢。你的提示解决了这个问题。我更改
handleKey
。如何取消注册?