做彩票网站需要什么服务器,python适合网站开发吗,厦门住房和建设局网站,企业网站建设实训建议在传统的 Java I/O 模型#xff08;BIO#xff09;中#xff0c;I/O 操作是以阻塞的方式进行的。也就是说#xff0c;当一个线程执行一个 I/O 操作时#xff0c;它会被阻塞直到操作完成。这种阻塞模型在处理多个并发连接时可能会导致性能瓶颈#xff0c;因为需要为每个连…在传统的 Java I/O 模型BIO中I/O 操作是以阻塞的方式进行的。也就是说当一个线程执行一个 I/O 操作时它会被阻塞直到操作完成。这种阻塞模型在处理多个并发连接时可能会导致性能瓶颈因为需要为每个连接创建一个线程而线程的创建和切换都是有开销的。
为了解决这个问题在 Java1.4 版本引入了一种新的 I/O 模型参考浅谈IO模型 — NIO New IO也称为 Non-blocking IO 。NIO 弥补了同步阻塞 I/O 的不足它在标准 Java 代码中提供了非阻塞、面向缓冲、基于通道的 I/O可以使用少量的线程来处理多个连接大大提高了 I/O 效率和并发。
NIO核心组成
Buffer缓冲区NIO 读写数据都是通过缓冲区进行操作的。读操作的时候将 Channel 中的数据填充到 Buffer 中而写操作时将 Buffer 中的数据写入到 Channel 中。Channel通道Channel 是一个双向的、可读可写的数据传输通道NIO 通过 Channel 来实现数据的输入输出。通道是一个抽象的概念它可以代表文件、套接字或者其他数据源之间的连接。Selector选择器允许一个线程处理多个 Channel基于事件驱动的 I/O 多路复用模型。所有的 Channel 都可以注册到 Selector 上由 Selector 来分配线程来处理事件。
关系如图所示: Buffer缓冲区
在 NIO 库中所有数据都是用缓冲区处理的这是新库和之前的 BIO 的一个重要区别有点类似于 BIO 中的缓冲流。NIO 在读取数据时它是直接读到缓冲区中的。在写入数据时写入到缓冲区中。 使用 NIO 在读写数据时都是通过缓冲区进行操作。Buffer 的子类如下图所示。其中最常用的是 ByteBuffer它可以用来存储和操作字节数据。 public abstract class Buffer {// Invariants: mark position limit capacity// Buffer允许将位置直接定位到该标记处这是一个可选属性private int mark -1;// 下一个可以被读写的数据的位置索引。从写操作模式到读操作模式切换的时候flipposition 都会归零这样就可以从头开始读写了。private int position 0;// Buffer 中可以读/写数据的边界。写模式下limit 代表最多能写入的数据一般等于 capacity可以通过limit(int newLimit)方法设置读模式下limit 等于 Buffer 中实际写入的数据大小。private int limit;// Buffer可以存储的最大数据量Buffer创建时设置且不可改变private int capacity;
}
Buffer 有读模式和写模式这两种模式分别用于从 Buffer 中读取数据或者向 Buffer 中写入数据。Buffer 被创建之后默认是写模式调用 flip() 可以切换到读模式。如果要再次切换回写模式可以调用 clear() 或者 compact() 方法。 Buffer 常用方法
get : 读取缓冲区的数据put 向缓冲区写入数据flip 将缓冲区从写模式切换到读模式它会将 limit 的值设置为当前 position 的值将 position 的值设置为 0。clear: 清空缓冲区将缓冲区从读模式切换到写模式并将 position 的值设置为 0将 limit 的值设置为 capacity 的值。
Channel通道
Channel 是一个通道它建立了与数据源如文件、网络套接字等之间的连接。我们可以利用它来读取和写入数据就像打开了一条自来水管让数据在 Channel 中自由流动。
BIO 中的流是单向的分为各种 InputStream输入流和 OutputStream输出流数据只是在一个方向上传输。通道与流的不同之处在于通道是双向的它可以用于读、写或者同时用于读写。
Channel 与前面介绍的 Buffer 打交道读操作的时候将 Channel 中的数据填充到 Buffer 中而写操作时将 Buffer 中的数据写入到 Channel 中。 Channel 是全双工的所以它可以比流更好地映射底层操作系统的 API。特别是在 UNIX 网络编程模型中底层操作系统的通道都是全双工的同时支持读写操作。
Channel 的子类如图所示。 常用的是以下几种类型的通道
FileChannel文件访问通道SocketChannel、ServerSocketChannelTCP 通信通道DatagramChannelUDP 通信通道
Channel 核心的两个方法
read 读取数据并写入到 Buffer 中。write 将 Buffer 中的数据写入到 Channel 中。
FileChannel读取文件数据
RandomAccessFile reader new RandomAccessFile(/Users/name/Documents/test.txt, r))
FileChannel channel reader.getChannel();
ByteBuffer buffer ByteBuffer.allocate(1024);
channel.read(buffer);
Selector选择器
Selector选择器 是 NIO 中的一个关键组件它允许一个线程处理多个 Channel。Selector 是基于事件驱动的 I/O 多路复用模型主要运作原理是通过 Selector 注册通道的事件Selector 会不断地轮询注册在其上的 Channel。当事件发生时比如某个 Channel 上面有新的 TCP 连接接入、读和写事件这个 Channel 就处于就绪状态会被 Selector 轮询出来。Selector 会将相关的 Channel 加入到就绪集合中。通过 SelectionKey 可以获取就绪 Channel 的集合然后对这些就绪的 Channel 进行响应的 I/O 操作。 一个多路复用器 Selector 可以同时轮询多个 Channel由于 JDK 使用了 epoll() 代替传统的 select 实现所以它并没有最大连接句柄 1024/2048 的限制。这也就意味着只需要一个线程负责 Selector 的轮询就可以接入成千上万的客户端。
Selector 可以监听以下四种事件类型
SelectionKey.OP_ACCEPT表示通道接受连接的事件这通常用于 ServerSocketChannel。SelectionKey.OP_CONNECT表示通道完成连接的事件这通常用于 SocketChannel。SelectionKey.OP_READ表示通道准备好进行读取的事件即有数据可读。SelectionKey.OP_WRITE表示通道准备好进行写入的事件即可以写入数据。
Selector是抽象类可以通过调用此类的 open() 静态方法来创建 Selector 实例。Selector 可以同时监控多个 SelectableChannel 的 IO 状况是非阻塞 IO 的核心。
一个 Selector 实例有三个 SelectionKey 集合
所有的 SelectionKey 集合代表了注册在该 Selector 上的 Channel这个集合可以通过 keys() 方法返回。被选择的 SelectionKey 集合代表了所有可通过 select() 方法获取的、需要进行 IO 处理的 Channel这个集合可以通过 selectedKeys() 返回。被取消的 SelectionKey 集合代表了所有被取消注册关系的 Channel在下一次执行 select() 方法时这些 Channel 对应的 SelectionKey 会被彻底删除程序通常无须直接访问该集合也没有暴露访问的方法。