Java NIO概述
传统的输入输出流都是阻塞的输入输出。举个列子:当用传统的流进行数据输入时,如果流中没有数据,它会阻塞当前线程往下执行,等到从流中读到数据为止。另外传统的输入输出流每次处理的是一个字节或一个字符,通常效率不是很高。从jdk 1.4开始 java提供了nio功能,可以代替传统的输入输出功能,在效率上也有很大提升。
标准的io基于字节流和字符流进行操作的,而nio是基于通道(channel)和缓冲区(buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中(双向操作)。nio可以使用非阻塞模式。
nio概述
nio在处理文件时会将文件的一段区域直接映射到内存中,这样访问文件时就可以像访问内存一样,比传统的输入输出要快很多。主要的实现类都在java.nio下面。
channe
l和buffer
是nio中两个核心的概念。channel的概念和传统的inputstram和outputstream对标,最大的区别是channel提供了一个map()方法将文件的块数据映射到内存中。可以面向一大块数据进行处理。buffer可以理解成缓冲,其本质是一个数组。从channel中读出来的数据要先存在buffer中,要写到channel中的数据也要先放到buffer中。
另外,nio还提供了将unicode字符串映射成字节序列的charset类,以及支持非阻塞输入输出的selector类。
channels and buffers
标准的io基于字节流和字符流进行操作的,而nio是基于通道(channel)和缓冲区(buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。channel、buffer和selectors是nio的核心组件。
channel常用的实现类:
- filechannel:文件
- datagramchannel:udp数据报
- socketchannel:tcp客户端
- serversocketchannel:tcp服务端
buffer常见实现类:
- bytebuffer
- charbuffer
- doublebuffer
- floatbuffer
- intbuffer
- longbuffer
- shortbuffer
buffer的使用
buffer的本质就是一个缓冲区,但是buffer提供了丰富的api来让我们操作这块数据区。
system.out.println("capacity:"+buffer.capacity()); system.out.println("limit:"+buffer.limit()); system.out.println("length:"+buffer.length()); system.out.println("position:"+buffer.position()); buffer.append("a"); buffer.append('b'); buffer.put('c'); system.out.println("---------------------------"); system.out.println("capacity:"+buffer.capacity()); system.out.println("limit:" + buffer.limit()); system.out.println("length:" + buffer.length()); system.out.println("position:" + buffer.position()); //flip方法会将limit的位置移动到当前posiion位置,这样buffer中没 //赋值的空间将都不能被访问。通常flip方法是为读取数据做准备的,可以 //防止读到null数据,读取完毕之后调用clear方法 buffer.flip(); system.out.println("---------------------------"); system.out.println("capacity:"+buffer.capacity()); system.out.println("limit:" + buffer.limit()); system.out.println("length:" + buffer.length()); system.out.println("position:" + buffer.position());
channel的使用
fileinputstream fis = new fileinputstream("file.txt"); filechannel channel = fis.getchannel(); bytebuffer buffer = bytebuffer.allocate(1024); int hasread = 0; while ((hasread=channel.read(buffer))>0){ byte[] buff = new byte[1024]; buffer.flip(); buffer.get(buff, 0, hasread); system.out.println(new string(buff,0,hasread)); buffer.clear(); }
selector
selector(选择器)是java nio中能够检测一到多个nio通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。与selector一起使用时,channel必须处于非阻塞模式下。这意味着不能将filechannel与selector一起使用,因为filechannel不能切换到非阻塞模式。而套接字通道都可以。
selector selector = selector.open(); channel.configureblocking(false); //注册到selector上 selectionkey key = channel.register(selector, selectionkey.op_read); while(true) { int readychannels = selector.select(); if(readychannels == 0) continue; set selectedkeys = selector.selectedkeys(); iterator keyiterator = selectedkeys.iterator(); while(keyiterator.hasnext()) { selectionkey key = keyiterator.next(); if(key.isacceptable()) { // a connection was accepted by a serversocketchannel. } else if (key.isconnectable()) { // a connection was established with a remote server. } else if (key.isreadable()) { // a channel is ready for reading } else if (key.iswritable()) { // a channel is ready for writing } keyiterator.remove(); } }
charset
用于对字符串编解码
jdk7的nio2
jdk 1.7版本对nio进行优化改进。path、paths和files这些类、filevisiter、watchservice asynchronousfilechannel
这些类进行文件内容的异步读写。asynchronoussocketchannel
这些类进行服务器io异步读写。
bio、nio和aio的区别
bio
(blocking i/o):同步阻塞i/o模式,数据的读取写入必须阻塞在一个线程内等待其完成。这里使用那个经典的烧开水例子,这里假设一个烧开水的场景,有一排水壶在烧开水,bio
的工作模式就是, 叫一个线程停留在一个水壶那,直到这个水壶烧开,才去处理下一个水壶。但是实际上线程在等待水壶烧开的时间段什么都没有做。(特点就是线程必须等待数据读取或者写入完成才能继续干其他事情。)nio
(new i/o):同时支持阻塞与非阻塞模式(文件channel只支持阻塞模式,socket的channel支持阻塞和非阻塞模式),但这里我们以其同步非阻塞i/o模式来说明,那么什么叫做同步非阻塞?如果还拿烧开水来说,nio
的做法是叫一个线程不断的轮询每个水壶的状态,看看是否有水壶的状态发生了改变,从而进行下一步的操作。(特点就是线程不必等待io读写完成,在io进行过程中线程可以不停地轮询io的状态,一旦发现io状态变化,就可以做出相应处理)-
aio
( asynchronous i/o):异步非阻塞i/o模型。异步非阻塞与同步非阻塞的区别在哪里?异步非阻塞无需一个线程去轮询所有io操作的状态改变,在相应的状态改变后,系统会通知对应的线程来处理。对应到烧开水中就是,为每个水壶上面装了一个开关,水烧开之后,水壶会自动通知我水烧开了。aio
中虽然不需要线程来轮询,但是需要线程来等待通知。另外,
aio
的异步特性并不是java实现的,而是使用了系统底层api的支持,在unix系统下,采用了epoll io模型,而windows便是使用了iocp模型。
参考
上一篇: PHP 常用数组函数详解
下一篇: 移动端常见问题(动画演示)