NIO的实战教程(简单且高效)

1. 参考

建议按顺序阅读以下三篇文章
为什么NIO被称为同步非阻塞?
Java IO 与 NIO:高效的输入输出操作探究
【Java.NIO】Selector,及SelectionKey

2. 实战

我们将模拟一个简单的HTTP服务器,它将响应客户端请求并返回一个固定的响应("Hello, World!")。我们将使用IO和NIO两种不同的方式实现此服务器。
2.1 传统阻塞IO

java 复制代码
import java.io.*;
public class TraditionalIOExample {
    public static void main(String[] args) {
        try {
            // 打开文件
            InputStream input = new FileInputStream("example.txt");
            OutputStream output = new FileOutputStream("output.txt");

            // 读取和写入数据
            int data;
            while ((data = input.read()) != -1) {
                output.write(data);
            }

            // 关闭文件
            input.close();
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.2 非阻塞NIO

java 复制代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class NioHttpServer {
    public static void main(String[] args) {
        try {
        	// 创建服务端通道
            ServerSocketChannel serverChannel = ServerSocketChannel.open();
            // 绑定访问端口
            serverChannel.socket().bind(new InetSocketAddress(8080));
            // 通道设置为非阻塞
            serverChannel.configureBlocking(false);

			// 通过open方法创建一个Selector
            Selector selector = Selector.open();
            /** 
            必须将channel注册到selector上,并订阅OP_ACCEPT事件
             		SelectionKey.OP_CONNECT  channel成功连接到另一个服务器称为"连接就绪"
					SelectionKey.OP_ACCEPT	 server socket channel准备好接收新进入的连接称为"接收就绪"
					SelectionKey.OP_READ	 有数据可读的通道可以说是"读就绪"
					SelectionKey.OP_WRITE	 有数据可写的通道可以说是"读就绪"
			*/
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);

            while (true) {
            	// 返回你所感兴趣的事件(连接,接受,读或写)已经准备就绪的那些通道
                int readyChannels = selector.select();
                if (readyChannels == 0){
                	continue;
                }
                // 访问"已选择键集"中的就绪通道
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                
                // 可以遍历这个已选择的集合来访问就绪的通道
                Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();
                    // 注意每次迭代末尾的remove()调用,Selector不会自己从已选择集中移除SelectioKey实例,必须在处理完通道时自己移除。
                    keyIterator.remove();

					// 一个server socket channel准备号接收新进入的连接称为"接收就绪"
                    if (key.isAcceptable()) {
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();
                        // 客户端socker注册进来
                        SocketChannel clientChannel = server.accept();
                        clientChannel.configureBlocking(false);
                        clientChannel.register(selector, SelectionKey.OP_READ);
                        // 客户端通道是否有数据流进来
                    } else if (key.isReadable()) {
                        SocketChannel clientChannel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        clientChannel.read(buffer);
                        buffer.flip();
                        byte[] bytes = new byte[buffer.remaining()];
                        buffer.get(bytes);
                        String request = new String(bytes);

                        String response = "HTTP/1.1 200 OK\r\n\r\nHello, World!\r\n";
                        ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());
                        clientChannel.write(responseBuffer);
                        clientChannel.close();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3. 模型

上述代码结合该模型,第二次阅读代码,会有更深的理解

4. 原理

多路复用才是NIO不阻塞的原因

相关推荐
JavaGuide4 小时前
JDK 25(长期支持版) 发布,新特性解读!
java·后端
用户3721574261354 小时前
Java 轻松批量替换 Word 文档文字内容
java
白鲸开源4 小时前
教你数分钟内创建并运行一个 DolphinScheduler Workflow!
java
Java中文社群4 小时前
有点意思!Java8后最有用新特性排行榜!
java·后端·面试
代码匠心5 小时前
从零开始学Flink:数据源
java·大数据·后端·flink
间彧5 小时前
Spring Boot项目中如何自定义线程池
java
间彧5 小时前
Java线程池详解与实战指南
java
用户298698530145 小时前
Java 使用 Spire.PDF 将PDF文档转换为Word格式
java·后端
渣哥5 小时前
ConcurrentHashMap 1.7 vs 1.8:分段锁到 CAS+红黑树的演进与性能差异
java
间彧5 小时前
复用线程:原理详解与实战应用
java