Java IO模型 BIO,NIO,AIO 详解

tech2026-02-10  1

阻塞式IO模型,BIO 

   JDK1.4 之前都是采用BIO模式(blocking I/O) ,阻塞式IO,模型如图

解释: 应用程序需要从磁盘读取数据分为两个阶段,1将磁盘数据复制到内核,2将内核数据复制到应用程序空间:

准备数据:应用程序问cpu说:我需要一个aaa.txt 文件,你去给我取来。CPU告诉应用程序,你等着我去给你准备数据(应用程序一直傻傻等待)。CPU转身问磁盘:磁盘我需要aaa.txt 文件,磁盘开始准备数据,并将数据复制到内核空间中(耗时) 等磁盘把数据给到CPU之后,告诉应用程序数据准备好了,现在给你,CPU将数据从内核复制到用户空间(耗时)

在上述两个阶段中,对于应用程序的一个线程来说发出读取文件指令后,这个线程都是一直在等待(阻塞),傻傻什么都不做,如果要想处理其他事情就需要其他线程来做。很明显这样的BIO模型性能很低,且消耗资源

jdk中java.io.* 包中都是基于阻塞式io实现的

代码:

public class BioMain { public static void main(String[] args) throws IOException { //服务端创建 ServerSocket serverSocket = new ServerSocket(1234); System.out.println("服务端启动,等待连接"); //可以一直接收客户端连接,但是只能有一个客户端可以读取数据 while (true) { //accept阻塞,serverSocket等待客户端的连接 Socket accept = serverSocket.accept(); System.out.println("来自客户端的连接:" + accept.getRemoteSocketAddress()); InputStream inputStream = accept.getInputStream(); Scanner scanner = new Scanner(inputStream); //针对一个客户端socket连接进行IO操作 while (true) { String line = scanner.nextLine();//阻塞,一直等待数据进来 if ("q".equals(line)){ break; } System.out.println("收到数据:" + line); accept.getOutputStream().write("I am server ask:".getBytes()); } } } }

 上述代码中只有一个main 线程,也就只能处理一个连接的请求,如果想处理多个请求,我们可以在服务端采用多线程的方式,也就对每个socket连接都分配一个线程

代码2:

public class BioMain2 { public static void main(String[] args) throws IOException { //服务端创建 ServerSocket serverSocket = new ServerSocket(1234); System.out.println("服务端启动,等待连接"); while (true) { //accept阻塞,serverSocket等待客户端的连接 Socket accept = serverSocket.accept(); System.out.println(Thread.currentThread().getName() + ":来自客户端的连接:" + accept.getRemoteSocketAddress()); new Thread(new Runnable() {//实际应用的时候替换成线程池 @Override public void run() { try { InputStream inputStream = accept.getInputStream(); Scanner scanner = new Scanner(inputStream); //针对一个客户端socket连接进行IO操作 while (true) { String line = scanner.nextLine();//阻塞,一直等待数据进来 if ("q".equals(line)) { break; } System.out.println(Thread.currentThread().getName() +"收到数据:" + line); accept.getOutputStream().write("I am server ask:".getBytes()); } } catch (IOException e) { e.printStackTrace(); } } }).start(); } } }  非阻塞式IO模型  NIO,Non-Blocking IO  

模型如图,应用进程向内核发出读取文件指令之后,内核就向磁盘发送指令准备数据去了,而应用进程不会阻塞等待去干其他事情了,过一会儿问问数据准备好了没,如果内核数据还没准备好,应用进程就继续干其他事情,一会儿一问数据好了没,这段时间中数据会从磁盘复制到内核空间,复制完成之后,待到应用进程再次询问的时候,内核就告诉它数据已经准备好了,在这个时候数据其实还是没有真正的进入到应用空间,此时应用进程又进入阻塞,等待数据从内核空间复制到应用空间,只不过这个阶段要比前一个阶段时间要短的多。总结就是第一个阶段不阻塞,第二个阶段阻塞

非阻塞式IO在Java中,jdk1.4以后有了一个java.nio.* 的包,Java中的nio实现其实是基于非阻塞式IO和多路复用IO模型实现的

IO复用模型

由于并不是所有的socket连接都要立马执行任务,IO复用模型,把所有的客户端连接都暂存到一个Map集合中,然后不断的循环遍历看哪些socket需要执行任务,就把它从map集合中获取处理进行处理

 

代码3:

public class NioMain { public static void main(String[] args) throws IOException { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); //设置为非阻塞方式 serverSocketChannel.configureBlocking(false); serverSocketChannel.bind(new InetSocketAddress(1234)); System.out.println("NIO 服务端开启成功。。。"); Selector selector = Selector.open(); //注册监听的事件 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //缓存区 ByteBuffer buffer = ByteBuffer.allocate(1024); while (true){ //循环监听客户端 int select = selector.select(); if (select==0){ continue; } Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = selectionKeys.iterator(); while (iterator.hasNext()){ SelectionKey selectionKey = iterator.next(); if (selectionKey.isAcceptable()){ ServerSocketChannel channel = (ServerSocketChannel) selectionKey.channel(); SocketChannel accept = channel.accept(); System.out.println("接收到客户端请求:"+accept.getRemoteAddress()); accept.configureBlocking(false); //将客户端过来的channel设置成读取状态 accept.register(selector,SelectionKey.OP_READ); } if (selectionKey.isReadable()){ SocketChannel channel = (SocketChannel) selectionKey.channel(); //通过channel将数据读取到缓存中 channel.read(buffer); String str = new String(buffer.array()); buffer.clear(); System.out.println("接收到数据:"+str+"——来自:"+channel.getRemoteAddress()); //回写数据 channel.write(ByteBuffer.wrap("I am form Nio Server".getBytes())); } iterator.remove(); } } } }

 

 

 

推荐:https://www.cnblogs.com/Jack-Blog/p/11991240.html

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

最新回复(0)