java - Selector.select 没有按预期阻塞

标签 java multithreading locking nio

在我当前的项目中,我注意到 select() 没有像预期的那样阻塞。 它根本不阻塞并总是返回,即使没有 IO 存在。所以我的 CPU 很忙。

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

文档对 selectNow() 说:

Invoking this method clears the effect of any previous invocations of the wakeup method.

所以我在每次迭代结束时调用该方法。没有成功。 我没有找到关于如何使用 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");
    }
}

最佳答案

OP_CONNECT 触发并且 finishConnect() 返回“true”之前,不要注册OP_READ。此时您必须注销 OP_CONNECT

同样,在您有东西要写之前,不要为 OP_WRITE 注册 channel 。 OP_WRITE 总是准备就绪,除非套接字发送缓冲区已满,因此它应该只在 检测到该情况后注册 (write()返回零),你应该在它触发时立即注销它(除非这种情况再次发生)。

最后 OP_CONNECTOP_WRITE 是相同的东西,鉴于我刚才所说的 OP_WRITE 解释了你的选择器旋转。

关于java - Selector.select 没有按预期阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7249421/

相关文章:

java - JTA EntityManager 不能使用 getTransaction()

java - 从 javascript 调用 java servlet

c++ - std::lock 的友元函数定义和替代 boost 函数

multithreading - TThreadList和 “with”语句

ios - 使用后台线程在 UICollectionViewCell 上加载视频以创建无缝滚动

c++ - 在类中正确使用 mutex、lock_guard、unique_lock

java - 如何从 Java 中的匿名内部类中获取对封闭类的引用?

java - 如何使用@KafkaListener spring boot 2消费者获取消费者id

java - Android Native C++,使用线程

multithreading - V8 内存限制可能会在 Node.js 应用程序中导致哪些不好的事情?