Java--IO--BIO、NIO、AIO 逃离我推掉我的手 2023-02-12 03:29 25阅读 0赞 原文网址:[Java--IO--BIO、NIO、AIO\_IT利刃出鞘的博客-CSDN博客][Java--IO--BIO_NIO_AIO_IT_-CSDN] # BIO、NIO、AIO # **其他网址** > [Java面试常考的 BIO,NIO,AIO 总结\_java\_小树的博客-CSDN博客][Java_ BIO_NIO_AIO _java_-CSDN] <table> <tbody> <tr> <td style="width:113px;"><strong>项</strong></td> <td style="width:227px;"><strong>BIO (Block IO)</strong></td> <td style="width:185px;"><strong>NIO (New IO)</strong></td> <td style="width:241px;"><strong>AIO(Asynchronous I/O)</strong></td> </tr> <tr> <td style="width:113px;"><strong>JDK版本</strong></td> <td style="width:227px;">所有版本</td> <td style="width:185px;">JDK1.4及之后</td> <td style="width:241px;">JDK1.7及之后</td> </tr> <tr> <td style="width:113px;"><strong>异步/阻塞</strong></td> <td style="width:227px;"> <p> 同步阻塞。</p> <p> <strong>一个连接一个线程。</strong>线程发起IO请求,不管内核是否准备好IO操作,从发起请求起,线程一直阻塞,直到操作完成。</p> <p> 数据的读取写入必须阻塞在一个线程内等待其完成。</p> </td> <td style="width:185px;"> <p> 同步阻塞/非阻塞。</p> <p> <strong>一个请求一个线程</strong>。客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。用户进程也需要时不时的询问IO操作是否就绪,这要求用户进程不停的去询问。</p> </td> <td style="width:241px;"> <p> 异步非阻塞。</p> <p> <strong>一个有效请求一个线程</strong>。用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。</p> </td> </tr> <tr> <td style="width:113px;"><strong>使用场景</strong></td> <td style="width:227px;"></td> <td style="width:185px;"> <p>适用于连接数目多且连接比较短(轻操作)的操作。例如:聊天服务器。</p> </td> <td style="width:241px;">适用于连接数目多且连接比较长(重操作)的架构。例如:相册服务器。</td> </tr> </tbody> </table> ## BIO ## **实例** > **客户端** > > public class IOClient { > public static void main(String[] args) { > // TODO 创建多个线程,模拟多个客户端连接服务端 > new Thread(() -> { > try { > Socket socket = new Socket("127.0.0.1", 3333); > while (true) { > try { > socket.getOutputStream().write((new Date() + ": hello world").getBytes()); > Thread.sleep(2000); > } catch (Exception e) { > } > } > } catch (IOException e) { > } > }).start(); > } > } > **服务端** > > public class IOServer { > public static void main(String[] args) throws IOException { > // TODO 服务端处理客户端连接请求 > ServerSocket serverSocket = new ServerSocket(3333); > // 接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理 > new Thread(() -> { > while (true) { > try { > // 阻塞方法获取新的连接 > Socket socket = serverSocket.accept(); > // 每一个新的连接都创建一个线程,负责读取数据 > new Thread(() -> { > try { > int len; > byte[] data = new byte[1024]; > InputStream inputStream = socket.getInputStream(); > // 按字节流方式读取数据 > while ((len = inputStream.read(data)) != -1) { > System.out.println(new String(data, 0, len)); > } > } catch (IOException e) { > } > }).start(); > } catch (IOException e) { > } > } > }).start(); > } > } ## NIO ## **其他网址** > [Java NIO原理与简单实现\_java\_lhrimperial的专栏-CSDN博客][Java NIO_java_lhrimperial_-CSDN] **简介** > JAVA NIO:新的IO(New I/O),其实是同一个概念。它是一种同步阻塞/非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题的有效方式。 > > NIO是一种基于通道和缓冲区的I/O方式,它可以使用Native函数库直接分配堆外内存(区别于JVM的运行时数据区),然后通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的直接引用进行操作。这样能在一些场景显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。 **实例** BIO部分的客户端 IOClient.java 的代码不变,我们对服务端使用 NIO 进行改造。 package org.example.a; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.util.Iterator; import java.util.Set; public class NIOServer { public static void main(String[] args) throws IOException { // 1. serverSelector负责轮询是否有新的连接,服务端监测到新的连接之后,不再创建一个新的线程, // 而是直接将新连接绑定到clientSelector上,这样就不用 IO 模型中 1w 个 while 循环在死等 Selector serverSelector = Selector.open(); // 2. clientSelector负责轮询连接是否有数据可读 Selector clientSelector = Selector.open(); new Thread(() -> { try { // 对应IO编程中服务端启动 ServerSocketChannel listenerChannel = ServerSocketChannel.open(); listenerChannel.socket().bind(new InetSocketAddress(3333)); listenerChannel.configureBlocking(false); listenerChannel.register(serverSelector, SelectionKey.OP_ACCEPT); while (true) { // 监测是否有新的连接,这里的1指的是阻塞的时间为 1ms if (serverSelector.select(1) > 0) { Set<SelectionKey> set = serverSelector.selectedKeys(); Iterator<SelectionKey> keyIterator = set.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isAcceptable()) { try { // (1)每来一个新连接,不需要创建一个线程,而是直接注册到clientSelector SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept(); clientChannel.configureBlocking(false); clientChannel.register(clientSelector, SelectionKey.OP_READ); } finally { keyIterator.remove(); } } } } } } catch (IOException ignored) { } }).start(); new Thread(() -> { try { while (true) { // (2) 批量轮询是否有哪些连接有数据可读,这里的1指的是阻塞的时间为 1ms if (clientSelector.select(1) > 0) { Set<SelectionKey> set = clientSelector.selectedKeys(); Iterator<SelectionKey> keyIterator = set.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isReadable()) { try { SocketChannel clientChannel = (SocketChannel) key.channel(); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); // (3) 面向 Buffer clientChannel.read(byteBuffer); byteBuffer.flip(); System.out.println( Charset.defaultCharset().newDecoder().decode(byteBuffer).toString()); } finally { keyIterator.remove(); key.interestOps(SelectionKey.OP_READ); } } } } } } catch (IOException ignored) { } }).start(); } } ## AIO ## **简介** > AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。 > > 目前来说 AIO 的应用还**不是很广泛**,Netty 之前也尝试使用过 AIO,不过又放弃了。 [Java--IO--BIO_NIO_AIO_IT_-CSDN]: https://knife.blog.csdn.net/article/details/106313912 [Java_ BIO_NIO_AIO _java_-CSDN]: https://blog.csdn.net/m0_38109046/article/details/89449305 [Java NIO_java_lhrimperial_-CSDN]: https://blog.csdn.net/u013857458/article/details/82424104
还没有评论,来说两句吧...