java NIO

来源:互联网 发布:海岛奇兵引导弹数据 编辑:程序博客网 时间:2024/06/18 13:33

NIO(non-blocking)非阻塞的IO,为传统的IO提供缓存支持。


一、概述
1、Channal
Channel如同流,数据可以从channel读到buffer中,也可以从buffer读到channel中。
Channel中有:FileCannel、DatagramChannel、SocketChannel、ServerSocketChannel
2、Buffer
Buffer中有:ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、ShortBuffer、LongBuffer,这8种对应java的8种基本类型。还有一个内存映射的MappedByteBuffer,是ByteBuffer的子类。
3、Selector
Selector允许单线程处理多个Channel。如果你的应用打开了多个连接(通道),但每个连 接流量很少,使用Selector就会很方便。
二、Channel
1、Channel(通道)和流:
1)数据既可以从通道中读出,也可以把数据读入到通道中,但是流是单向的
2)通道可以异步读取
3)通道的数据总是读到一个Buffer中,或者从一个Buffer读到通道中

2、Channel的实现
Channel中有:FileCannel、DatagramChannel、SocketChannel、ServerSocketChannel
FileChannel:从文件中读取数据。
DatagramChannel:能通过UDP读取网络中的数据。
SocketChannel:能通过TCP读取网络中的数据。
ServerSocketChannel:可以监听新来的TCP连接,如同WEB服务器一样。为每个新来的TCP连接创建SocketChannel。
三、Buffer
1、Buffer的基本用法
1)写入数据到Buffer,buffer会记录多少数据
2)调用flip()方法,将Buffer的写模式换成读模式,在读模式下,可以读到之前写入到buffer里面的数据。
3)从Buffer里读取数据
4)调用clear()或者compact()方法,清空buffer,clear方法是清空所有的缓存,compact是清空已读的缓存,未读的数据依然存在,新写入的数据放到未读数据的后面。
2、Buffer的三个属性capacity、position、limit
1)capacity,作为一个内存块,Buffer有固定的大小,只能往里面写capacity个byte、int等类型,若Buffer满了,需要将其清空,才可以继续写数据。
2)position,写数据的时候:position表示当前位置,初始值为0,最大值为capacity-1
读数据的时候:从某个位置读数据,当Buffer从写模式变为读模式的时候,position 会置为0,当从position处读数据的时候,position向前移动到下一个可读的位置。
3)limit,写模式:limit表示最多写多少个,limit等于capacity
读模式:limit表示最多读多少个,当buffer到读模式的时候,limit会设置成写模式的 position。
3、Buffer的常用方法
buffer的分配:allocate(capacity)
写入数据到Buffer:Channel写入(inChannel.read(buf))和buffer的put方法(bf.put(long))
flip()方法:将写模式换成读模式,将position置为0,将limit值置为position
读数据从Buffer:读数据到Channel(inChannel..write(buf))和buffer的get方法(buf.get())
rewind()方法:rewind()方法将position置为0,limit不变,重新读取数据
clear()和compact()方法:清空数据,clear()方法清空所有的,将positon置为0,limit置为capacity,compact()方法清空已读的数据,position置为未读的数据的后一位,limit置为capacity
mark()和reset()方法:mark()方法,标记一个特定的position,之后通过reset()的方法恢复到这个position。
四、Scatter/Gather
scatter和gather用于描述从Channel读取数据或者写入到Channel中去的操作。
分散(scatter)从Channel中读取是指在读操作的时候讲Channel中的数据分散然后读入到多个buffer中。
聚集(gather)写入Channel是指在写操作的时候,从多个buffer聚集到一起,然后写入到一个Channel。
ByteBuffer first = ByteBuffer.allocate(1024);
ByteBuffer second = ByteBuffer.allocate(1024);
ByteBuffer [] buffArr = {first,second};
SocketChannel channel =(SocketChannel)selectionKey.channel();
channel.read(buffArr);//分散
channel.write(buffArr);//聚集
五、通道间数据传输
1、transferFrom()
将数据从源通道传输到目的通道中。
toChannel.transferFrom(position, count, fromChannel);
2、transferTo()
将数据从FileChannel传输到其他的通道中
fromChannel.transferTo(position, count, toChannel);
六、Selector
1、Selector(选择器)是java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。Selector仅用单个线程来处理多个Channel的好处是只需要更少的线程来处理通道。
2、Selector的使用
Selector select = Selector.open()//创建Selector
channel.configureBlocking(false)//设置非阻塞
SelectionKey key = channel.register(selector,SelectionKey.OP_READ)
register可以监控4种类型的事件,Connect、Accept、Read、Write
3、SelectionKey
上面的register方法返回一个SelectionKey,SelectionKey包含interset集合、ready集合、Channel、Selector
七、ServerSocketChannel
ServerSocketChannel可以监听新进来的TCP连接的通道,想标准的IO中的ServerSocket一样。

八、IO和NIO的区别
IO
NIO
面向流
面向缓冲
阻塞IO
非阻塞IO
选择器(Selector)
面向流和面向缓冲:
Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。
阻塞和非阻塞:
Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。 Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。