20220422java学习笔记-------------NIO

20220422java学习笔记-------------NIO,第1张

高并发IO的底层原理 IO读写的基本原理

应用程序的IO *** 作实际上不是物理设备级别的读写,而是缓存的复制。 (底层的读写交换系统内核完成,在内核缓冲区和进程缓冲区之间进行数据交换。)

内核缓冲区与进程缓冲区

内核缓冲区:减少底层系统的频繁中断所导致的时间损耗、性能损耗。(只有一个)

进程缓冲区:每个用户程序(进程)都有自己独立的缓冲区。

read:内核到进程

write:进程到内核

IO *** 作就是内核缓冲区和进程缓冲区之间的数据交换

系统调用流程

数据交换流程 

Linux系统文件句柄数量默认值为1024 

在开机启动文件设置

ulimit -SHn 1000000

-S软性极限值  超出报警

-H硬性极限值  不能超出

要彻底解除Linux系统的最大文件打开数量的限制,可以通过编辑Linux的极限配置文件/etc/security/limits.conf来做到。修改此文件,加入如下内容:soft nofile 1000000 hard nofile 1000000soft nofile表示软性极限,hard nofile表示硬性极限。

java NIO java NIO(异步非阻塞IO、 New IO)

NIO弥补了原来面向流的OIO同步阻塞的不足,为标准Java代码提供了高速、面向缓冲区的IO。

NIO和OIO的对比

1)OIO是面向流(Stream Oriented)的,NIO是面向缓冲区(Buffer Oriented)的。

2)OIO的 *** 作是阻塞的,而NIO的 *** 作是非阻塞的。

3)OIO没有选择器(Selector)的概念,而NIO有选择器的概念。

三个核心组件

channel(通道)

一个通道类似于OIO中两个流的结合体,既可以从通道读取数据,也可以向通道写入数据。

buffer(缓冲区)

完成NIO的非阻塞读写 *** 作,缓冲区的使用是面向流进行读写 *** 作的OIO所没有的

selector(选择器)

一个线程可以查询多个通道的IO事件的就绪状态。底层的 *** 作系统IO多路复用技术的支持。

NIO Buffer 

1)Buffer本质上是一个内存块(数组)。写入和读取的交替访问

2)Buffer类是一个抽象类,位于java.nio包中,有8种缓冲区类,分别是ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer、MappedByteBuffer

3)Buffer类是一个非线程安全类。

4)记录读写的状态和位置

 Buffer的成员属性

NIO Buffer重要方法 

 allocate(x)

实例Buffer对象 空间大小为x*4个字节

put()

写入元素到缓冲区

flip()

将写模式转换成读模式

clean()

清空缓冲区,可以将模式重置为读模式

(1)将position清零。

(2)limit设置为capacity最大容量值,可以一直写入,直到缓冲区写满。

compact()

压缩,可以将模式重置为读模式

get()

读取缓冲区数据

rewind()

重新读取

mark()

记住当前位置(position)的值保存到mark(标签)中

rest()

把Mark的值恢到position中

注意:Buffer.mark()和Buffer.reset()两个方法都涉及mark属性的使用。mark()方法与mark属性的名字虽然相同,但是一个是Buffer类的成员方法,一个是Buffer类的成员属性,不能混淆。

Buffer类的基本步骤

NIO Channel

(1)FileChannel:文件通道,用于文件的数据读写。更高效文件复制通道的transferFrom()方法

(2)SocketChannel:套接字通道,用于套接字TCP连接的数据读写,可以在服务端和客户端

(3)ServerSocketChannel:服务器套接字通道(或服务器监听通道),允许我们监听TCP连接请求,为每个监听到的请求创建一个SocketChannel通道,只能在服务端

(4)DatagramChannel:数据报通道,用于UDP的数据读写。

无论是ServerSocketChannel还是SocketChannel,都支持阻塞和非阻塞两种模式。如何进行模式的设置呢?调用configureBlocking()方法

(1)socketChannel.configureBlocking(false)设置为非阻塞模式。

(2)socketChannel.configureBlocking(true)设置为阻塞模式。

在阻塞模式下,SocketChannel的连接、读、写 *** 作都是同步阻塞式的,在效率上与Java OIO面向流的阻塞式读写 *** 作相同。

在非阻塞模式下,通道的 *** 作是异步、高效的,这也是相对于传统OIO的优势所在。

 

NIO Selector (选择器) 选择器与注册

完成IO的多路复用,其主要工作是通道的注册、监听、事件查询。选择器和通道的关系是监听和被监听的关系。

一个单线程处理一个选择器,一个选择器可以监控很多通道。

通道和选择器之间的关联通过register(注册)的方式完成。调用通道的Channel.register(Selector sel,int ops)方法,可以将通道实例注册到一个选择器中。register方法有两个参数:第一个参数指定通道注册到的选择器实例;第二个参数指定选择器要监控的IO事件类型。可供选择器监控的通道IO事件类型包括以下四种:

(1)可读:SelectionKey.OP_READ。

(2)可写:SelectionKey.OP_WRITE。

(3)连接:SelectionKey.OP_CONNECT。

(4)接收:SelectionKey.OP_ACCEPT。

 什么是IO事件?

这里的IO事件不是对通道的IO *** 作,而是通道处于某个IO *** 作的就绪状态,表示通道具备执行某个IO *** 作的条件。

SelectableChannel(可选择通道)

实现通道可选择性所需要的公共方法。

一个通道若能被选择,则必须继承SelectableChannel类。

 SelectionKey

SelectionKey就是那些被选择器选中的IO事件。选择器中注册过,就会被选择器选中,并放入SelectionKey中可以获得通道的IO事件类型(比如SelectionKey.OP_READ),还可以获得发生IO事件所在的通道。

选择器使用流程 

注: 处理完成后,需要将选择键从SelectionKey集合中移除,以防止下一次循环时被重复处理。SelectionKey集合不能添加元素,如果试图向SelectionKey中添加元素,则将抛出java.lang.UnsupportedOperationException异常。

select()方法

用于选择就绪的IO事件的select()方法有多个重载的实现版本,具体如下:

(1)select():阻塞调用,直到至少有一个通道发生了注册的IO事件。

(2)select(long timeout):和select()一样,但最长阻塞时间为timeout指定的毫秒数。

(3)selectNow():非阻塞,不管有没有IO事件都会立刻返回。

select()方法的返回值是整数类型(int),表示发生了IO事件的数量,即从上一次select到这一次select之间有多少通道发生了IO事件,更加准确地说是发生了选择器感兴趣(注册过)的IO事件数。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/langs/870862.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-13
下一篇2022-05-13

发表评论

登录后才能评论

评论列表(0条)

    保存