国外工业设计网站,ue5培训机构哪家强,软件开发公司推荐,做微网站的公司哪家好呢目录
一. 前言
二. IO 模型
2.1. IO 模型分类
2.2. BIO、NIO、AIO 使用场景分析
2.3. NIO 和 BIO 的比较
三. BIO#xff08;同步阻塞#xff09;
3.1. BIO 编程流程
3.2. BIO 应用实例
3.3. 问题分析
四. NIO#xff08;同步非阻塞#xff09;
4.1. 基本介绍
…目录
一. 前言
二. IO 模型
2.1. IO 模型分类
2.2. BIO、NIO、AIO 使用场景分析
2.3. NIO 和 BIO 的比较
三. BIO同步阻塞
3.1. BIO 编程流程
3.2. BIO 应用实例
3.3. 问题分析
四. NIO同步非阻塞
4.1. 基本介绍
4.1.1. 选择器Selector
4.1.2. 通道Channel
4.2. NIO 三大核心原理示意图
4.3. 缓冲区Buffer
4.3.1. 基本介绍
4.3.2. Buffer 类及其子类
4.3.3. ByteBuffer
4.4. 通道Channel
4.4.1 基本介绍
4.4.2. FileChannel 类
4.4.2.1. 应用实例1 - 本地文件写数据
4.4.2.2. 应用实例2 - 本地文件读数据
4.4.2.3. 应用实例3 - 使用一个 Buffer 完成文件读取、写入
4.4.2.4. 应用实例4 - 拷贝文件 transferFrom 方法
4.4.3. 关于 Buffer 和 Channel 的注意事项和细节
4.5. Selector选择器
4.5.1. 基本介绍
4.5.2. Selector 类相关方法
4.6. NIO 非阻塞网络编程原理分析图
五. AIO异步非阻塞
5.1. 基本介绍
5.2. AIO 的特点
5.3. AIO 的应用
六. 总结 一. 前言 在 Java 编程中IOInput/Output操作是非常常见的操作它涉及到文件读写、网络通信等方面。Java 提供了各种类来支持这些操作。本文将从 IO 的基础知识讲起逐步深入介绍 Java IO 的各个方面。 Java IOInput/Output是 Java 语言中用于读写数据的 API它提供了一系列类和接口用于读取和写入各种类型的数据。下面是 Java IO 发展史的简要介绍
JDK 1.01996年 最初的 Java IO 只支持字节流InputStream、OutputStream和字符流Reader、Writer两种基于阻塞式 IOBIO模型。JDK 1.11997年 JDK 1.1 引入了 NIONew IO包支持了缓存区Buffer、通道Channel等概念提供了更高效的 IO 操作方式可以实现非阻塞式 IONIO模式。JDK 1.42002年 JDK 1.4 增加了 NIO.2 API也称为 Java NIO with buffers提供了更强大的文件处理功能和更高效的 IO 操作。JDK 72011年 JDK 7 引入了 NIO.2 的改进版——NIO.2 with Completion Ports也称为AIOAsynchronous IO支持异步 IO 方式在处理大量并发请求时具有优势。
二. IO 模型
2.1. IO 模型分类 Java BIO同步并阻塞传统阻塞型服务器实现模式为一个连接一个线程即客户端有连接请求时服务器端就需要启动一个线程进行处理如果这个连接不做任何事情会造成不必要的线程开销。 BIO 模型 Java NIO同步非阻塞服务器实现模式为一个线程处理多个请求连接即客户端发送的连接请求都会注册到多路复用器上多路复用器轮询到连接有 I/O 请求就进行处理。 NIO 模型 Java AIONIO.2异步非阻塞AIO 引入异步通道的概念采用了 Proactor 模式简化了程序编写有效的请求才启动线程它的特点是先由操作系统完成后才通知服务端程序启动线程去处理一般适用于连接数较多且连接时间较长的应用。
2.2. BIO、NIO、AIO 使用场景分析 BIO 方式适用于连接数目比较小且固定的架构这种方式对服务器资源要求比较高并发局限于应用中JDK1.4 以前的唯一选择但程序简单易理解。 NIO 方式适用于连接数目多且连接比较短轻操作的架构比如聊天服务器弹幕系统服务器间通讯等。编程比较复杂JDK1.4 开始支持。 AIO 方式使用于连接数目多且连接比较长重操作的架构比如相册服务器充分调用 OS 参与并发操作编程比较复杂JDK7 开始支持。
2.3. NIO 和 BIO 的比较
1. BIO 以流的方式处理数据而 NIO 以块的方式处理数据块 I/O 的效率比流 I/O 高很多。
2. BIO 是阻塞的NIO 则是非阻塞的。
3. BIO 基于字节流和字符流进行操作而 NIO 基于 Channel通道和 Buffer缓冲区进行操作数据总是从通道读取到缓冲区中或者从缓冲区写入到通道中。Selector选择器用于监听多个通道的事件比如连接请求数据到达等因此使用单个线程就可以监听多个客户端通道。
4. Buffer和Channel之间的数据流向是双向的。
三. BIO同步阻塞
3.1. BIO 编程流程
1. 服务器端启动一个 ServerSocket。
2. 客户端启动 Socket 对服务器进行通信默认情况下服务器端需要对每个客户端建立一个线程与之通讯。
3. 客户端发出请求后先咨询服务器是否有线程响应如果没有则会等待或者被拒绝。
4. 如果有响应客户端线程会等待请求结束后再继续执行。 Blocking I/O
3.2. BIO 应用实例
package com.lm.bio;import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class BIOServer { public static void main(String[] args) throws Exception {// 线程池机制// 思路// 1. 创建一个线程池// 2. 如果有客户端连接就创建一个线程与之通讯(单独写一个方法)ExecutorService newCachedThreadPool Executors.newCachedThreadPool();// 创建ServerSocketServerSocket serverSocket new ServerSocket(6666);System.out.println(服务器启动了);while (true) {System.out.println(线程信息id Thread.currentThread().getId() 名字 Thread.currentThread().getName());// 监听等待客户端连接System.out.println(等待连接....);// 会阻塞在accept()final Socket socket serverSocket.accept();System.out.println(连接到一个客户端);// 就创建一个线程与之通讯(单独写一个方法)newCachedThreadPool.execute(new Runnable() {public void run() { // 重写// 可以和客户端通讯handler(socket);}});}}// 编写一个handler方法和客户端通讯public static void handler(Socket socket) {try {System.out.println(线程信息id Thread.currentThread().getId() 名字 Thread.currentThread().getName());byte[] bytes new byte[1024];// 通过socket获取输入流InputStream inputStream socket.getInputStream();// 循环的读取客户端发送的数据while (true) {System.out.println(线程信息id Thread.currentThread().getId() 名字 Thread.currentThread().getName());System.out.println(read....);int read inputStream.read(bytes);if (read ! -1) {System.out.println(new String(bytes, 0, read)); // 输出客户端发送的数据} else {break;}}} catch (Exception e) {e.printStackTrace();} finally {System.out.println(关闭和client的连接);try {socket.close();} catch (Exception e) {e.printStackTrace();}}}
} 打开 telnet 客户端输入 open 127.0.0.1 6666 命令会一直显示“正在连接127.0.0.1...”这时其实已经连上此时按下 Ctrl] 键连接成功 出现 Microsoft Telnet就可以用命令 send 发送消息了。
3.3. 问题分析
1. 每个请求都需要创建独立的线程与对应的客户端进行数据 Read业务处理数据 Write。
2. 当并发数较大时需要创建大量线程来处理连接系统资源占用较大。
3. 连接建立后如果当前线程暂时没有数据可读则线程就阻塞在 Read 操作上造成线程资源浪费。
四. NIO同步非阻塞
4.1. 基本介绍 NIO 有三大核心部分Channel通道、Buffer缓冲区、Selector选择器。 NIO 是面向缓冲区或者面向块编程的。数据读取到一个它稍后处理的缓冲区需要时可在缓冲区中前后移动这就增加了处理过程中的灵活性使用它可以提供非阻塞式的高伸缩性网络。 Java NIO 的非阻塞模式使一个线程从某通道发送请求或者读取数据但是它仅能得到目前可用的数据如果目前没有数据可用时就什么都不会获取而不是保持线程阻塞所以直至数据变得可以读取之前该线程可以继续做其他的事情。非阻塞写也是如此一个线程请求写入一些数据到某通道但不需要等待它完全写入这个线程同时可以去做别的事情。 通俗理解NIO 是可以做到用一个线程来处理多个操作的。假设有 10000 个请求过来根据实际情况可以分配 50 或者 100 个线程来处理。不像之前的阻塞 IO 那样非得分配 10000 个。
4.1.1. 选择器Selector 选择器是 Java NIO 中的一个重要组件它可以用于同时监控多个通道的读写事件并在有事件发生时立即做出响应。选择器可以实现单线程监听多个通道的效果从而提高系统吞吐量和运行效率。
4.1.2. 通道Channel 通道是一个用于读写数据的对象类似于 Java IO 中的流Stream。与流不同的是通道可以进行非阻塞式的读写操作并且可以同时进行读写操作。通道分为两种类型FileChannel 和SocketChannel分别用于文件和网络通信。
4.2. NIO 三大核心原理示意图 每个 Channel 都会对应一个 Buffer。Selector 对应一个线程一个线程对应多个 Channel连接。该图反应了有三个 Channel 注册到该 Selector //程序程序切换到哪个 Channel 是由事件决定的Event 就是一个重要的概念。Selector 会根据不同的事件在各个通道上切换。Buffer 就是一个内存块底层是有一个数组。数据的读取写入是通过 Buffer这个和 BIO 是不同的BIO 中要么是输入流或者是输出流不能双向但是 NIO 的 Buffer 是可以读也可以写需要 flip 方法切换 Channel 是双向的可以返回底层操作系统的情况比如 Linux底层的操作系统通道就是双向的。
4.3. 缓冲区Buffer
4.3.1. 基本介绍 缓冲区Buffer缓冲区本质上是一个可以读写数据的内存块可以理解成是一个容器对象含数组该对象提供了一组方法可以更轻松地使用内存块缓冲区对象内置了一些机制能够跟踪和记录缓冲区的状态变化情况。缓冲区对象包含了一些状态变量例如容量capacity、限制limit、位置position等用于控制数据的读写。Channel 提供从文件、网络读取数据的渠道但是读取或写入的数据都必须经由 Buffer如图 4.3.2. Buffer 类及其子类
在 NIO 中Buffer 是一个顶层父类它是一个抽象类类的层级关系图 Buffer 类定义了所有的缓冲区都具有的四个属性来提供关于其所包含的数据元素的信息 Buffer 类相关方法一览
public abstract class Buffer {// JDK1.4 时引入的 APIpublic final int capacity(); // 返回此缓冲区的容量public final int position(); // 返回此缓冲区的位置public final Buffer position(int newPosition); // 设置此缓冲区的位置public final int limit(); // 返回此缓冲区的限制public final Buffer limit(int newLimit); // 设置此缓冲区的限制public final Buffer mark(); // 在此缓冲区的位置设置标记public final Buffer reset(); // 将此缓冲区的位置重置为以前标记的位置public final Buffer clear(); // 清除此缓冲区即将各个标记恢复到初始状态但是数据并没有真正擦除public final Buffer flip(); // 反转此缓冲区public final Buffer rewind(); // 重绕此缓冲区public final int remaining(); // 返回当前位置与限制之间的元素数public final boolean hasRemaining(); // 告知在当前位置和限制之间是否有元素public abstract boolean isReadOnly(); //告知此缓冲区是否为只读缓冲区// JDK1.6 时引入的 APIpublic abstract boolean hasArray(); // 告知此缓冲区是否具有可访问的底层实现数组public abstract Object array(); // 返回此缓冲区的底层实现数组public abstract int arrayOffset(); // 返回此缓冲区的底层实现数组中第一个缓冲区元素的偏移量public abstract boolean isDirect(); // 告知此缓冲区是否为直接缓冲区
}
4.3.3. ByteBuffer 从前面可以看出对于 Java 中的基本数据类型boolean 除外都有一个 Buffer 类型与之相对应最常用的自然是 ByteBuffer 类二进制数据该类的主要方法如下
public abstract class ByteBuffer {// 缓冲区创建相关 APIpublic static ByteBuffer allocateDirect(int capacity); // 创建直接缓冲区public static ByteBuffer allocate(int capacity); // 设置缓冲区的初始容量public static ByteBuffer wrap(byte[] array); // 把一个数组放到缓冲区中使用public static ByteBuffer wrap(byte[] array, int offset, int length); // 构造初始化位置 offset 和上界 length 的缓冲区// 缓冲区存取相关 APIpublic abstract byte get(); // 从当前位置position上getget之后position会自动1public abstract byte get(int index); // 从绝对位置getpublic abstract ByteBuffer put(byte b); // 从当前位置上putput之后position会自动1public abstract ByteBuffer put(int index, byte b); // 从绝对位置上put
}
4.4. 通道Channel
4.4.1 基本介绍
NIO 的通道类似于流但有些区别如下
通道可以同时进行读写而流只能读或者只能写通道可以实现异步读写数据通道可以从缓冲读数据也可以写数据到缓冲。 BIO 中的 Stream 是单向的例如 FileInputStream 对象只能进行读取数据的操作而 NIO 中的通道Channel是双向的可以读操作也可以写操作。Channel 在 NIO 中是一个接口 public interface Channel extends Closeable {}。 常用的 Channel 类有FileChannel、DatagramChannel、ServerSocketChannel 和 SocketChannel。ServerSocketChanne 类似 ServerSocket、SocketChannel 类似 Socket FileChannel 用于文件的数据读写DatagramChannel 用于 UDP 的数据读写ServerSocketChannel 和 SocketChannel 用于 TCP 的数据读写。 4.4.2. FileChannel 类
FileChannel 主要用来对本地文件进行 IO 操作常见的方法有
public int read(ByteBuffer dst); // 从通道读取数据并放到缓冲区中
public int write(ByteBuffer src); //把缓冲区的数据写到通道中
public long transferFrom(ReadableByteChannel src, long position, long count); // 从目标通道中复制数据到当前通道
public long transferTo(long position, long count, WritableByteChannel target); // 把数据从当前通道复制给目标通道
4.4.2.1. 应用实例1 - 本地文件写数据
使用前面学习后的 ByteBuffer缓冲和 FileChannel通道将 “hello流华追梦” 写入到 file01.txt 中
package com.lm.nio;import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;public class NIOFileChannel01 {public static void main(String[] args) throws Exception {String str hello流华追梦;// 创建一个输出流 - channelFileOutputStream fileOutputStream new FileOutputStream(d:\\file01.txt);// 通过 fileOutputStream 获取对应的 FileChannel// 这个 fileChannel 真实类型是 FileChannelImplFileChannel fileChannel fileOutputStream.getChannel();// 创建一个缓冲区 ByteBufferByteBuffer byteBuffer ByteBuffer.allocate(1024);// 将 str 放入 byteBufferbyteBuffer.put(str.getBytes());// 对 byteBuffer 进行 flipbyteBuffer.flip();// 将 byteBuffer 数据写入到 fileChannelfileChannel.write(byteBuffer);fileOutputStream.close();}
}
4.4.2.2. 应用实例2 - 本地文件读数据
使用前面学习后的 ByteBuffer缓冲和 FileChannel通道将 file01.txt 中的数据读入到程序并显示在控制台屏幕
package com.lm.nio;import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;public class NIOFileChannel02 {public static void main(String[] args) throws Exception {// 创建文件的输入流File file new File(d:\\file01.txt);FileInputStream fileInputStream new FileInputStream(file);// 通过 fileInputStream 获取对应的 FileChannel - 实际类型 FileChannelImplFileChannel fileChannel fileInputStream.getChannel();// 创建缓冲区ByteBuffer byteBuffer ByteBuffer.allocate((int)file.length());// 将通道的数据读入到 BufferfileChannel.read(byteBuffer);// 将 byteBuffer 的字节数据转成 StringSystem.out.println(new String(byteBuffer.array()));fileInputStream.close();}
}
4.4.2.3. 应用实例3 - 使用一个 Buffer 完成文件读取、写入
使用 FileChannel通道和方法 read、write完成文件的拷贝 package com.lm.nio;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;public class NIOFileChannel03 {public static void main(String[] args) throws Exception {FileInputStream fileInputStream new FileInputStream(1.txt);FileChannel fileChannel01 fileInputStream.getChannel();FileOutputStream fileOutputStream new FileOutputStream(2.txt);FileChannel fileChannel02 fileOutputStream.getChannel();ByteBuffer byteBuffer ByteBuffer.allocate(512);while (true) { // 循环读取// 这里有一个重要的操作一定不要忘了/*public final Buffer clear() {position 0;limit capacity;mark -1;return this;}*/byteBuffer.clear(); // 清空 bufferint read fileChannel01.read(byteBuffer);System.out.println(read read);if (read -1) { // 表示读完break;}// 将 buffer 中的数据写入到 fileChannel02--2.txtbyteBuffer.flip();fileChannel02.write(byteBuffer);}// 关闭相关的流fileInputStream.close();fileOutputStream.close();}
}
4.4.2.4. 应用实例4 - 拷贝文件 transferFrom 方法
使用 FileChannel通道和方法 transferFrom完成文件的拷贝
package com.lm.nio;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;public class NIOFileChannel04 {public static void main(String[] args) throws Exception {// 创建相关流FileInputStream fileInputStream new FileInputStream(d:\\a.jpg);FileOutputStream fileOutputStream new FileOutputStream(d:\\a2.jpg);// 获取各个流对应的 FileChannelFileChannel sourceCh fileInputStream.getChannel();FileChannel destCh fileOutputStream.getChannel();// 使用 transferForm 完成拷贝destCh.transferFrom(sourceCh, 0, sourceCh.size());// 关闭相关通道和流sourceCh.close();destCh.close();fileInputStream.close();fileOutputStream.close();}
}
4.4.3. 关于 Buffer 和 Channel 的注意事项和细节
ByteBuffer 支持类型化的 put 和 getput 放入的是什么数据类型get 就应该使用相应的数据类型来取出否则可能有 BufferUnderflowException 异常
package com.lm.nio;import java.nio.ByteBuffer;public class NIOByteBufferPutGet {public static void main(String[] args) {// 创建一个 BufferByteBuffer buffer ByteBuffer.allocate(64);// 类型化方式放入数据buffer.putInt(100);buffer.putLong(9);buffer.putChar(尚);buffer.putShort((short) 4);// 取出buffer.flip();System.out.println();System.out.println(buffer.getInt());System.out.println(buffer.getLong());System.out.println(buffer.getChar());System.out.println(buffer.getShort());}
}
可以将一个普通 Buffer 转成只读 Buffer
package com.lm.nio;import java.nio.ByteBuffer;public class ReadOnlyBuffer {public static void main(String[] args) {// 创建一个 bufferByteBuffer buffer ByteBuffer.allocate(64);for (int i 0; i 64; i) {buffer.put((byte) i);}// 读取buffer.flip();// 得到一个只读的 BufferByteBuffer readOnlyBuffer buffer.asReadOnlyBuffer();System.out.println(readOnlyBuffer.getClass());// 读取while (readOnlyBuffer.hasRemaining()) {System.out.println(readOnlyBuffer.get());}readOnlyBuffer.put((byte) 100); //ReadOnlyBufferException}
}
NIO 还提供了 MappedByteBuffer可以让文件直接在内存堆外的内存中进行修改而如何同步到文件由 NIO 来完成
package com.lm.nio;import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;/*** 说明 1.MappedByteBuffer 可让文件直接在内存堆外内存修改,操作系统不需要拷贝一次*/
public class MappedByteBufferTest {public static void main(String[] args) throws Exception {RandomAccessFile randomAccessFile new RandomAccessFile(1.txt, rw);// 获取对应的通道FileChannel channel randomAccessFile.getChannel();/*** 参数 1:FileChannel.MapMode.READ_WRITE 使用的读写模式* 参数 20可以直接修改的起始位置* 参数 3:5: 是映射到内存的大小不是索引位置即将 1.txt 的多少个字节映射到内存* 可以直接修改的范围就是 0-5* 实际类型 DirectByteBuffer*/MappedByteBuffer mappedByteBuffer channel.map(FileChannel.MapMode.READ_WRITE, 0, 5);mappedByteBuffer.put(0, (byte) H);mappedByteBuffer.put(3, (byte) 9);mappedByteBuffer.put(5, (byte) Y);//IndexOutOfBoundsExceptionrandomAccessFile.close();System.out.println(修改成功~~);}
}
前面我们讲的读写操作都是通过一个 Buffer 完成的NIO 还支持通过多个 Buffer即 Buffer 数组完成读写操作即 Scattering 和 Gathering
package com.lm.nio;import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Arrays;/*** Scattering将数据写入到 buffer 时可以采用 buffer 数组依次写入 [分散]* Gathering从 buffer 读取数据时可以采用 buffer 数组依次读*/
public class ScatteringAndGatheringTest {public static void main(String[] args) throws Exception { // 使用 ServerSocketChannel 和 SocketChannel 网络ServerSocketChannel serverSocketChannel ServerSocketChannel.open();InetSocketAddress inetSocketAddress new InetSocketAddress(7000);// 绑定端口到 socket并启动serverSocketChannel.socket().bind(inetSocketAddress);// 创建 buffer 数组ByteBuffer[] byteBuffers new ByteBuffer[2];byteBuffers[0] ByteBuffer.allocate(5);byteBuffers[1] ByteBuffer.allocate(3);// 等客户端连接 (telnet)SocketChannel socketChannel serverSocketChannel.accept();int messageLength 8; // 假定从客户端接收 8 个字节// 循环的读取while (true) {int byteRead 0;while (byteRead messageLength) {long l socketChannel.read(byteBuffers);byteRead l; // 累计读取的字节数System.out.println(byteRead byteRead);// 使用流打印,看看当前的这个 buffer 的 position 和 limitArrays.asList(byteBuffers).stream().map(buffer - position buffer.position() , limit buffer.limit()).forEach(System.out::println);}// 将所有的 buffer 进行 flipArrays.asList(byteBuffers).forEach(buffer - buffer.flip());// 将数据读出显示到客户端long byteWirte 0;while (byteWirte messageLength) {long l socketChannel.write(byteBuffers);//byteWirte l;}// 将所有的buffer进行clearArrays.asList(byteBuffers).forEach(buffer - {buffer.clear();});System.out.println(byteRead byteRead , byteWrite byteWirte , messagelength messageLength);}}
}
4.5. Selector选择器
4.5.1. 基本介绍
Java 的 NIO用非阻塞的 IO 方式。可以用一个线程处理多个的客户端连接就会使用到 Selector选择器。
Selector 能够检测多个注册的通道上是否有事件发生注意多个 Channel 以事件的方式可以注册到同一个 Selector如果有事件发生便获取事件然后针对每个事件进行相应的处理。这样就可以只用一个单线程去管理多个通道也就是管理多个连接和请求。
只有在连接/通道真正有读写事件发生时才会进行读写就大大地减少了系统开销并且不必为每个连接都创建一个线程不用去维护多个线程。
避免了多线程之间的上下文切换导致的开销。 Nonblocking I/O
4.5.2. Selector 类相关方法
Selector 在是一个抽象类常用方法说明如下 4.6. NIO 非阻塞网络编程原理分析图 对上图的说明
当客户端连接时会通过 ServerSocketChannel 得到 SocketChannel。Selector 进行监听 select 方法返回有事件发生的通道的个数。将 socketChannel 注册到 Selector 上register(Selector sel, int ops)一个 Selector 上可以注册多个 SocketChannel。注册后返回一个 SelectionKey会和该 Selector 关联集合。进一步得到各个 SelectionKey有事件发生。在通过 SelectionKey 反向获取 SocketChannel方法 channel()。可以通过得到的 channel完成业务处理。
五. AIO异步非阻塞
5.1. 基本介绍 JDK7 引入了 Asynchronous I/O即 AIO。在进行 I/O 编程中常用到两种模式Reactor 和 Proactor。Java 的 NIO 就是 Reactor当有事件触发时服务器端得到通知进行相应的处理。 AIO 即 NIO2.0叫做异步不阻塞的 IO。AIO 引入异步通道的概念采用了 Proactor 模式简化了程序编写有效的请求才启动线程它的特点是先由操作系统完成后才通知服务端程序启动线程去处理一般适用于连接数较多且连接时间较长的应用。 AIO 使用了三个核心组件AsynchronousChannel、CompletionHandler 和 AsynchronousServerSocketChannel。其中AsynchronousChannel 是读/写数据的通道CompletionHandler 是 I/O 操作完成时的回调方法AsynchronousServerSocketChannel 是异步服务器端套接字通道用于监听客户端的连接请求。
5.2. AIO 的特点
1. 高并发性Java AIO 采用异步 IO 方式进行数据读写操作可以实现高并发处理能力。
2. 高吞吐量Java AIO 支持异步读写操作可以同时处理多个请求从而提高了数据读写的效率和吞吐量。
3. 高可靠性由于Java AIO 采用异步 IO 方式进行数据读写操作可以避免线程阻塞等待 I/O 操作完成的情况从而提高程序的可靠性。
4. 简单易用Java AIO 提供了简单易用的 API不需要编写复杂的代码就可以实现异步 IO 操作。
5.3. AIO 的应用 Java AIO 适用于需要大量并发连接但每个连接却很少有数据交互的场景例如基于消息的应用程序、远程过程调用RPC等。在这些应用场景中AIO 可以大幅度提高程序的性能和并发处理能力从而满足用户对高吞吐量和低延迟的要求。 另外Java AIO 也可以用于开发高性能的网络服务器例如聊天室服务器、在线游戏服务器等。由于 AIO 支持异步读取输入流和输出流因此可以同时处理多个客户端请求有效地提高了服务器的并发处理能力。
六. 总结
BIO、NIO、AIO 对比表 BIONIOAIOIO模型同步阻塞同步非阻塞多路复用异步非阻塞编程难度简单复杂复杂可靠性差好好吞吐量低高高