大家好,又见面了,我是你们的朋友全栈君。
java 1.4版本推出了一种新型的IO API,与原来的IO具有相同的作用和目的;可代替标准java IO,只是实现的方式不一样,NIO是面向缓冲区、基于通道的IO操作;通过NIO可以提高对文件的读写操作。基于这种优势,现在使用NIO的场景越来愈多,很多主流行的框架都使用到了NIO技术,如Tomcat、Netty、Jetty等;所以学习和掌握NIO技术已经是一个java开发的必备技能了。
NIO | IO |
---|---|
面向缓冲区Buffer | 面向流Stream |
双向(基于通道Channel) | 单向(分别建立输入流、输出流) |
同步非阻塞(non-blocking) | 同步阻塞 |
选择器(Selector,多路复用) | 无 |
支持字符集编码解码解决方案,支持锁,支持内存映射文件的文件访问接口 | 无 |
主要包括:缓冲区(Buffer)、通道(Channel)和选择器(Selector)、字符集(Charset);首先获取用于连接IO设备的通道channel以及用于容纳数据的缓冲区,利用选择器Selector监控多个Channel的IO状况(多路复用),然后操作缓冲区,对数据进行处理。 NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择器)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道,即一个单独的线程现在可以管理多个输入和输出通道。
在javaNIO中负责数据的存取,底层缓冲区就是数组,用于存储不同数据类型的数据,根据不同的数据类型(Boolean除外),提供了相应类型的缓冲区:ByteBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer、CharBuffer。这7种数据类型的Buffer都是通过allocate获取非直接缓冲区或allocateDirect(ByteBuffer通过此方式创建)或wrap(除ByteBuffer意外其他的创建方式)获取直接缓冲区域,分配一个指定大小的缓冲区。 代码实例:Java NIO之缓存Buffer代码实例
通过:static ByteBuffe allocate(int capacity)创建指定大小的缓冲区,在JVM内存中创建,在每次调用基础操作系统的一个本机IO之前或者之后,虚拟机都会将缓冲区的内容复制到中间缓冲区(或者从中间缓冲区复制内容),缓冲区的内容驻留在JVM内,因此销毁容易,但是占用JJVM内存开销,处理过程中有复杂的操作。
通过:static ByteBuffer allocateDirect(int capacity)字节Buffer创建指定大小的缓冲区,其他类型的Buffer通过wrap()方法创建缓冲区;在JVM内存外开辟空间,在每次调用基础操作系统的一个本机IO之前或者之后,虚拟机都会避免将缓冲区的内容复制到中间缓冲区(或者从缓冲区中复制内容),缓冲区的内容驻留在屋里内存中,少一次复制过程,如果需要循环使用缓冲区,用直接缓冲区可以很大地提高性能;虽然直接缓冲区可以使JVM进行高效的I/O操作,但它使用的内存使操作系统分配的,绕过了JVM堆栈,建立和销毁比堆栈上的缓存区要更大的开销。
Channel表示到IO设备(如:文件、套接字)的连接,即用于源节点与目标节点的连接,在java NIO中Channel本身不负责存储数据,主要是配合缓冲区,负责数据的传输。 代码实例:Java NIO之通道Channel代码实例
使用Channel的实现类的对应方法(在直接缓冲区):transferForm()和transferTo()
是selectableChannel的多路复用器,用于监控SelectableChannel的IO状况。利用selector可以实现在一个线程中管理多个通道Channel,selector是非阻塞IO的核心。 SelectableChannel的结构图:
表示SelectableChannel在Selector中的注册的标志,每次向选择器注册通道的时候就会选择一个事件(以上四种事件类型)即选择键,选择键包含两个表示位整数值的操作集(分别为interst集合和ready集合),操作集的每一位都表示该键的通道所支持的一类可选择操作。
方法/属性 | 描述 |
---|---|
interset集合 | Selector感兴趣的集合,用于指示选择器对管道关心的操作,可通过SelectionKey对象的interestOps()获取;最初,该兴趣集合是通过通道被注册到Selector时传进来的值。该集合不会被选择器改变,但是可以通过interestOps()改变,我们可以通过以下方法判断Selector是否对Channel的某种事件感兴趣:int interestSet=selectionKey.interestOps(); boolean isInterestedInAccept =(interestSet&SelectionKey.OP_ACCEPT)==SelectionKey.OP_ACCEPT |
read集合 | 通道已经就绪的操作的集合,表示一个通道准备好要执行的操作了,可通过SelectionKey对象的readOps()来获取相关通道已经就绪的操作。它是interest集合的子集,并且表示interest集合中从上次调用select()以后已经就绪的那些操作。 //int readSet=selectionKey.readOps();selectionKey.isAcceptable();//等价于selectionKey.readyOps()SelectionKey.OP_ACCEPT;selectionKey.isConnectable();selectionKey.isReadable();selectionKey.isWritable(); |
int interestOps() | 获取感兴趣事件集合 |
int readyOps() | 获取通道已经准备就绪的操作的集合 |
SelectableChannel channel() | 获取注册通道 |
Selector selector() | 返回选择器 |
boolean isReadable() | 检查Channel中读事件是否就绪 |
boolean isWriteable() | 检测Channel 中写事件是否就绪 |
boolean isConnectable() | 检测Channel中连接是否就绪 |
boolean isAcceptable() | 检测Channel中接收是否就绪 |
方法 | 描述 |
---|---|
Set< SelectionKey > keys() | 所有的SelectionKey集合,代表注册在该Selector上的Channel |
selectedKeys() | 被选择的SelectionKey集合。返回此Selector的已选择键集 |
int select() | 监控所有注册的Channel,当它们中间有需要处理的IO操作时,该方法返回,并将对应的SelectionKey加入被选择的SelectionKey集合中,该方法返回这些Channel的数量。 |
int select(long timeout) | 可以设置超时时长的select()操作 |
int selectNow() | 执行一个立即返回的select()操作,该方法不会阻塞线程 |
Selector wakeUp() | 使一个还未返回的select()方法立即返回 |
void close() | 关闭该选择器 |
字符串转成字节数组
字节数组转成字符串
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/156730.html原文链接:https://javaforall.cn