无代码开发平台排名,鹤壁网站优化,网络工程是什么,找在家做的兼职上什么网站好文章目录
目录 文章目录
前言
一、BIO#xff08;Blocking I/O#xff09;#xff1a;同步阻塞模型
核心机制#xff1a;
1.示例
二、NIO#xff08;Non-blocking I/O#xff09;#xff1a;同步非阻塞模型
1.Buffer
底层结构
核心属性
总结
channal: Sele… 文章目录
目录 文章目录
前言
一、BIOBlocking I/O同步阻塞模型
核心机制
1.示例
二、NIONon-blocking I/O同步非阻塞模型
1.Buffer
底层结构
核心属性
总结
channal: Selector选择器多路复用控制器
总结
代码示例 三、AIO
四、redis中的多路复用和NIO中的多路复用
四、总结 前言
BIO-NIO-AIO的转变历程
传统BIO的问题在于高并发时的线程开销而NIO通过多路复用减少了线程数量提高了并发能力。但NIO的编程模型复杂需要处理事件循环、缓冲区管理等。AIO则进一步简化利用操作系统的异步支持实现真正的非阻塞但可能在某些系统上支持不够好比如Linux的AIO实现不如Windows成熟所以Netty还是基于NIO。 一、BIOBlocking I/O同步阻塞模型
核心机制 每个连接对应一个线程线程在读写操作时会被阻塞直到数据就绪。 1.示例
直接看一个代码示例 socket建立连接发送数据对于每个连接创建一个线程实现异步通信
首先需要了解BIO的阻塞点1.连接2.读写
// 服务端代码
public class BioServer {public static void main(String[] args) throws IOException {ServerSocket server new ServerSocket(8080);System.out.println(BIO 服务端启动监听端口 8080...);while (true) {// 阻塞点1等待客户端连接没有连接时线程挂起Socket client server.accept(); System.out.println(客户端连接 client.getRemoteSocketAddress());// 为每个连接创建新线程处理读写new Thread(() - {try {// 阻塞点2读取客户端数据无数据时线程挂起InputStream in client.getInputStream();BufferedReader reader new BufferedReader(new InputStreamReader(in));String line;while ((line reader.readLine()) ! null) { // 阻塞直到有数据System.out.println(收到客户端消息: line);// 阻塞点3向客户端写回数据输出流满时阻塞OutputStream out client.getOutputStream();out.write((服务端响应: line \n).getBytes());out.flush();}} catch (IOException e) {e.printStackTrace();}}).start();}}
}
这里使用多线程的方式虽然解决了单线程阻塞的情况但是对每个连都创建一个线程进行读写如果这时候连接多了线程太大占用的资源可想而知
二、NIONon-blocking I/O同步非阻塞模型
为什么会出现NIO呢其实就是为了解决BIO单线程阻塞问题读写阻塞连接阻塞实现单线程解决并发问题多路复用
核心机制 多路复用器Selector轮询事件单线程处理多个连接核心是非阻塞和事件驱动。
关键组件 Channel通道双向通信替代BIO的流支持非阻塞模式。 Buffer缓冲区数据读写的中转区需配合 flip()、clear() 操作。 Selector选择器监控多个通道的事件如连接、读、写。
1.Buffer
底层结构
Buffer的底层实现是一个数组具体类型取决于Buffer的子类例如
ByteBuffer底层是byte[]数组IntBuffer底层是int[]数组其他类型如CharBuffer、DoubleBuffer等同理。
核心属性
java nio包下看到buffer类里面有这4个核心属性 capacity数组的固定长度创建后不可变。例如ByteBuffer.allocate(10)会分配一个长度为10的byte[]数组。 position指向下一个待读写的位置初始为0每次读写后自动递增。 limit读写操作的上限。写模式下limit等于capacity读模式下limit等于有效数据的末尾位置由flip()方法设置。 mark通过mark()方法保存position的某个状态后续可通过reset()恢复到此位置。
总结
Buffer本质上是封装了数组的内存块通过capacity容量、position读写位置、limit操作上限、mark标记位四个属性管理数据流。例如ByteBuffer底层是byte[]数组其他类型如IntBuffer同理
核心功能 缓冲作用在I/O操作中Channel通道与Buffer配合实现数据的批量读写。例如写数据时先填充Buffer再批量写入Channel减少直接操作磁盘或网络的次数提升效率。 状态切换通过flip()切换读写模式写模式下limitcapacity读模式下limitposition以及clear()/compact()清空或压缩数据。 channal:
定位替代传统 BIO 的 Stream提供双向数据传输能力。
底层接口 主要实现类
类名用途FileChannel文件 I/O不支持非阻塞模式SocketChannelTCP 网络套接字客户端/服务端ServerSocketChannelTCP 服务端监听套接字DatagramChannelUDP 数据报通道Pipe.SinkChannel/SourceChannel线程间通信通道 Selector选择器多路复用控制器
单线程管理多个通道的核心组件实现 1个线程处理1000连接。
是NIO的核心通过监控多个Channal 实现单个线程并发处理多个请求 selector也位于channals包下 总结 NIO模型中每个连接无论是客户端连接还是服务端监听都对应一个Channel将这些Channel注册到同一个Selector上由Selector统一监控这些Channel的I/O事件如读、写、连接等。Selector的核心作用就是用一个线程管理多个Channel实现高并发。 代码示例
服务器端
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 nioTest {private static final int PORT 8080;private static final int BUFFER_SIZE 1024;public static void main(String[] args) throws IOException {// 1. 创建Selector多路复用器Selector selector Selector.open();// 2. 创建ServerSocketChannel并配置非阻塞ServerSocketChannel serverChannel ServerSocketChannel.open();serverChannel.configureBlocking(false); // 关键设置为非阻塞模式serverChannel.bind(new InetSocketAddress(PORT));// 3. 注册ACCEPT事件到SelectorserverChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println(NIO 服务端启动监听端口: PORT);// 4. 事件循环单线程处理所有连接while (true) {// 阻塞等待就绪的通道可设置超时int readyChannels selector.select(1000); // 等待1秒if (readyChannels 0) {System.out.println(等待事件中...);continue;}// 5. 获取就绪的SelectionKey集合SetSelectionKey selectedKeys selector.selectedKeys();IteratorSelectionKey keyIterator selectedKeys.iterator();while (keyIterator.hasNext()) {SelectionKey key keyIterator.next();// 6. 处理连接事件if (key.isAcceptable()) {handleAccept(key, selector);}// 7. 处理读事件if (key.isReadable()) {handleRead(key);}// 8. 处理写事件通常只在需要时注册if (key.isWritable()) {handleWrite(key);}// 9. 移除已处理的Key必须keyIterator.remove();}}}// 处理新连接private static void handleAccept(SelectionKey key, Selector selector)throws IOException {ServerSocketChannel serverChannel (ServerSocketChannel) key.channel();// 10. 接受连接非阻塞立即返回SocketChannel clientChannel serverChannel.accept();if (clientChannel null) return;System.out.println(客户端连接: clientChannel.getRemoteAddress());// 11. 配置客户端通道为非阻塞clientChannel.configureBlocking(false);// 12. 注册读事件并附加BufferclientChannel.register(selector,SelectionKey.OP_READ,ByteBuffer.allocate(BUFFER_SIZE) // 附加Buffer对象);}// 处理读数据private static void handleRead(SelectionKey key) throws IOException {SocketChannel clientChannel (SocketChannel) key.channel();ByteBuffer buffer (ByteBuffer) key.attachment(); // 获取附加的Buffer// 13. 非阻塞读取不会长时间阻塞int bytesRead clientChannel.read(buffer);if (bytesRead -1) { // 客户端关闭连接System.out.println(客户端断开: clientChannel.getRemoteAddress());clientChannel.close();return;}if (bytesRead 0) {// 14. 切换Buffer为读模式buffer.flip();// 15. 处理数据简单打印byte[] data new byte[buffer.remaining()];buffer.get(data);String message new String(data);System.out.println(收到数据: message);// 16. 准备写回响应注册写事件key.interestOps(SelectionKey.OP_WRITE);// 17. 保存响应数据实际应用应更复杂key.attach(ByteBuffer.wrap((ECHO: message).getBytes()));// 18. 清空Buffer或compact()处理半包buffer.clear();}}// 处理写数据private static void handleWrite(SelectionKey key) throws IOException {SocketChannel clientChannel (SocketChannel) key.channel();ByteBuffer buffer (ByteBuffer) key.attachment();// 19. 非阻塞写入while (buffer.hasRemaining()) {clientChannel.write(buffer);}// 20. 重新注册读事件取消写事件key.interestOps(SelectionKey.OP_READ);// 21. 重置Buffer为下次读准备buffer.clear();}
}
客户端
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Scanner;public class NioClient {public static void main(String[] args) throws IOException, InterruptedException {// 1. 创建SocketChannel非阻塞SocketChannel socketChannel SocketChannel.open();socketChannel.configureBlocking(false);// 2. 异步连接服务器立即返回socketChannel.connect(new InetSocketAddress(127.0.0.1, 8080));// 3. 等待连接完成非阻塞方式while (!socketChannel.finishConnect()) {System.out.println(连接建立中...);Thread.sleep(300); // 模拟其他操作}System.out.println(连接服务器成功);// 4. 用户输入循环Scanner scanner new Scanner(System.in);while (true) {System.out.print(输入消息: );String message scanner.nextLine();// 5. 非阻塞写入ByteBuffer buffer ByteBuffer.wrap(message.getBytes());while (buffer.hasRemaining()) {socketChannel.write(buffer);}// 6. 非阻塞读取响应ByteBuffer readBuffer ByteBuffer.allocate(1024);int bytesRead socketChannel.read(readBuffer);if (bytesRead 0) {readBuffer.flip();byte[] data new byte[readBuffer.remaining()];readBuffer.get(data);System.out.println(收到响应: new String(data));}}}
} 三、AIO
核心机制 异步回调或Future机制由操作系统完成IO操作后通知应用无需应用线程等待。
关键组件 AsynchronousServerSocketChannel异步处理连接。 CompletionHandler 或 Future处理完成事件或获取结果。
工作流程 服务端通过 accept() 异步接收连接立即返回。 操作系统完成连接建立后回调 CompletionHandler。 读写操作同理数据就绪后触发回调。
四、redis中的多路复用和NIO中的多路复用
redis也使用了多路复用但是底层
组件Java NIORedis语言JavaC 语言底层依赖JVM 封装的 epoll/kqueue直接调用操作系统的 epoll/kqueue实现级别JVM 用户空间操作系统内核空间 四、总结 持续更新