当前位置: 移动技术网 > IT编程>开发语言>Java > Java NIO概述

Java NIO概述

2020年03月17日  | 移动技术网IT编程  | 我要评论

传统的输入输出流都是阻塞的输入输出。举个列子:当用传统的流进行数据输入时,如果流中没有数据,它会阻塞当前线程往下执行,等到从流中读到数据为止。另外传统的输入输出流每次处理的是一个字节或一个字符,通常效率不是很高。从jdk 1.4开始 java提供了nio功能,可以代替传统的输入输出功能,在效率上也有很大提升。

标准的io基于字节流和字符流进行操作的,而nio是基于通道(channel)和缓冲区(buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中(双向操作)。nio可以使用非阻塞模式。

nio概述

nio在处理文件时会将文件的一段区域直接映射到内存中,这样访问文件时就可以像访问内存一样,比传统的输入输出要快很多。主要的实现类都在java.nio下面。

channel和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模型

参考

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网