zoukankan      html  css  js  c++  java
  • Java NIO概述

    传统的输入输出流都是阻塞的输入输出。举个列子:当用传统的流进行数据输入时,如果流中没有数据,它会阻塞当前线程往下执行,等到从流中读到数据为止。另外传统的输入输出流每次处理的是一个字节或一个字符,通常效率不是很高。从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模型

    参考

    公众号推荐

    欢迎大家关注我的微信公众号「程序员自由之路」

  • 相关阅读:
    序列
    2018131
    成都七中
    NOIP2017
    洛谷P1352 CodeVS1380 没有上司的舞会
    BZOJ1087 SCOI2005 互不侵犯King
    11-4-2017 星期六 R-Day?
    11-3-2017 星期五
    11-2-2017 星期四
    USACO 2014 US Open, Silver Problem 2. Dueling GPSs
  • 原文地址:https://www.cnblogs.com/54chensongxia/p/12509281.html
Copyright © 2011-2022 走看看