JAVA NIO

概述

NIO库是在JDK 1.4中引入的。JDK1.7升级了NIO类库,升级后的NIO类库被称为NIO2.0。在这篇文章中,我们只介绍JDK中的NIO2。NETTY其实就是基于NIO2(注意有部分是自己实现的,比如说对epoll的使用)。https://stackoverflow.com/questions/23465401/why-native-epoll-support-is-introduced-in-netty
以下的NIO均指NIO2。
JAVA NIO会根据操作系统的种类和版本决定使用哪一种系统调用来实现NIO。对于Linux,常见的有epoll,poll,select。在Linux 2.6+版本,Java NIO采用的epoll(即EPollSelectorImpl类),对于2.4.x的,则使用poll(即PollSelectorImpl类)。

NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector。传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。

使用NIO一定要注意NIO臭名昭著的epoll空轮训BUG。selector的轮训(select)结果为空的情况下,则就相当于while循环满载,会迅速耗尽CPU资源。Netty对这个BUG进行了简单解决,就是对某段时间内的空轮训进行计数,如果超过设定值则会重建select,将原有的Channel从旧的Selector上去除注册,重新注册到新的Selector上,并将原来的Selector关闭。

https://www.cnblogs.com/JAYIT/p/8241634.html

类图

这里写图片描述
这里写图片描述
这里写图片描述

基本用法

        System.out.println("Listening on port " + port);
        ServerSocketChannel serverChannel = ServerSocketChannel.open();// 打开一个未绑定的serversocketchannel
        ServerSocket serverSocket = serverChannel.socket();// 得到一个ServerSocket去和它绑定 
        Selector selector = Selector.open();// 创建一个Selector供下面使用
        serverSocket.bind(new InetSocketAddress(port));//设置server channel将会监听的端口
        serverChannel.configureBlocking(false);//设置非阻塞模式
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);//将ServerSocketChannel注册到Selector
        while (true) 
        {
            // This may block for a long time. Upon returning, the
            // selected set contains keys of the ready channels.
            int n = selector.select();
            if (n == 0) 
            {
                continue; // nothing to do
            }           
            java.util.Iterator<SelectionKey> it = selector.selectedKeys().iterator();// Get an iterator over the set of selected keys
            //在被选择的set中遍历全部的key
            while (it.hasNext()) 
            {
                SelectionKey key = (SelectionKey) it.next();
                // 判断是否是一个连接到来
                if (key.isAcceptable()) 
                {
                    ServerSocketChannel server =(ServerSocketChannel) key.channel();
                    SocketChannel channel = server.accept();
                    registerChannel(selector, channel,SelectionKey.OP_READ);//注册读事件
                    sayHello(channel);//对连接进行处理
                }
                //判断这个channel上是否有数据要读
                if (key.isReadable()) 
                {
                    readDataFromSocket(key);
                }
                //从selected set中移除这个key,因为它已经被处理过了
                it.remove();
            }
        }
阅读更多

没有更多推荐了,返回首页