java的nio是水平触发吗

2019-04-26  本文已影响0人  不存在的里皮

java的nio是水平触发吗?在linux上,其实现是基于linux epoll的。所以首先我们要了解epoll。

epoll 水平触发

epoll 水平触发与边缘触发一文中讲述了水平触发的条件:

  1. 对于读操作
    只要缓冲内容不为空,LT模式返回读就绪。
  2. 对于写操作
    只要缓冲区还不满,LT模式会返回写就绪。

所以,Linux epoll的水平触发是以缓冲区空满状态来判断的

那java nio是水平触发吗

首先我们知道了,Linux epoll的水平触发是以缓冲区空满状态来判断的。
所以,验证java nio水平触发的办法是客户端写多个字节(比如1000个),服务端每次都不读取字节,缓冲区一直没读完,处于非空状态。由于水平触发,读事件应当会一直触发。
如果能多次触发读事件,就应当是水平触发,我们用以下代码验证:
在下列代码中:

服务端:

public class NioServer {
    public static void main(String[] argv) throws Exception {
        Selector selector = Selector.open();
        ServerSocketChannel server = ServerSocketChannel.open();
        server.bind(new InetSocketAddress("0.0.0.0", 1339));
        server.configureBlocking(false);
        server.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            int n = selector.select();
            if (n == 0) continue;

            System.out.println("Select " + n);

            Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
            while (keys.hasNext()) {
                SelectionKey key = keys.next();
                keys.remove();
                if (key.isAcceptable()) {
                    ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                    SocketChannel accept = channel.accept();
                    accept.configureBlocking(false);
                    accept.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    SocketChannel channel = (SocketChannel) key.channel();

                    // 不读取任何数据
                }
            }
            System.out.println("休眠一秒, 减缓输出, 便于观察");
            Thread.sleep(1000);
        }
    }
}

客户端:

public class NioClient
{
    private static SocketChannel socketChannel = null;

    private static Charset charset = Charset.forName("GBK");

    public static void init() throws IOException
    {
        socketChannel = SocketChannel.open();
        InetAddress ia = InetAddress.getLocalHost();
        InetSocketAddress isa = new InetSocketAddress(ia, 1339);
        socketChannel.connect(isa);
        socketChannel.configureBlocking(false);
        System.out.println("与服务器的连接建立成功!");
    }
    
    public static void main(String[] args) throws InterruptedException, IOException {
        init();
        socketChannel.write(charset.encode("hello world"));
    }

}

输出

客户端
服务端

现象

结论

只要缓冲区非空,就能一直触发读取事件。所以linux中,java nio是水平触发的

上一篇下一篇

猜你喜欢

热点阅读