Java NIO

154 阅读4分钟

1、Java NIO的简介

  • NoBlockingIO或者是NewIO。是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。

2、IO与NIO的区别

IO NIO
面向流 面向缓冲区
阻塞 非阻塞
选择器

3、通道channel

  • Java NIO系统的核心在于:通道channel和缓冲区。通道表示打开到IO 设备(例如:文件、套接字)的连接。若需要使用NIO 系统,需要获取用于连接IO 设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理

  • 通道不负责存储数据,负责数据的传输,Buffer负责存储。Channel 本身不能直接访问数据,Channel 只能与Buffer 进行交互。

  • 实现类

    • FileChannel:用于读取、写入、映射和操作文件的通道。 • DatagramChannel:通过UDP 读写网络中的数据通道。 • SocketChannel:通过TCP 读写网络中的数据。 • ServerSocketChannel:可以监听新进来的TCP 连接,对每一个新进来的连接都会创建一个SocketChannel。

4、缓冲区Buffer

  • 一个用于特定基本数据类型的容器。由java.nio 包定义的,所有缓冲区都是Buffer 抽象类的子类。

  • Java NIO中的Buffer 主要用于与NIO 通道进行交互,数据是从通道读入缓冲区,从缓冲区写入通道中的。

  • 缓冲区Buffer底层就是一个数组,可以保存多个相同类型的数据,Boolean除外。

  • allocate()方法分配缓冲区的。

  • get和put方法

  • capacity表示缓冲区的最大容量,缓冲区的容量不能为负,一旦创建之后不能更改

  • limit表示第一个不能读取或者写入的数据的索引,也就是limit后面的数据不能读取或者写入。不能为负,小于等于最大容量。

  • position表示下一个读取或者写入的数据的索引,不能为负。不能大于limit

  • rewind(),重复读。

  • clear(),清空缓冲区,但是里面的数据并没有被清空,里面的数据处于被遗忘状态

  • mark和reset,mark是记录当前position的位置,可以使用reset回到记录的位置。

  • 0<=mark<=position<=limit<=capacity

    		ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            System.out.println("----------------allocate-----------------");
            System.out.println(byteBuffer.position());
            System.out.println(byteBuffer.capacity());
            System.out.println(byteBuffer.limit());
            String a = "abc";
            byteBuffer.put(a.getBytes());
            System.out.println("----------------put-----------------");
            System.out.println(byteBuffer.position());
            System.out.println(byteBuffer.capacity());
            System.out.println(byteBuffer.limit());
            byteBuffer.flip();
            System.out.println("----------------flip-----------------");
            System.out.println(byteBuffer.position());
            System.out.println(byteBuffer.capacity());
            System.out.println(byteBuffer.limit());
            byte[] det = new byte[byteBuffer.limit()];
            byteBuffer.get(det);
            System.out.println("----------------get-----------------");
            System.out.println(byteBuffer.position());
            System.out.println(byteBuffer.capacity());
            System.out.println(byteBuffer.limit());
            System.out.println(new String(det, 0, det.length));
            byteBuffer.rewind();
            System.out.println("----------------rewind-----------------");
            System.out.println(byteBuffer.position());
            System.out.println(byteBuffer.capacity());
            System.out.println(byteBuffer.limit());
            byteBuffer.clear();
            System.out.println("----------------clear-----------------");
            System.out.println(byteBuffer.position());
            System.out.println(byteBuffer.capacity());
            System.out.println(byteBuffer.limit());
    

    5、直接缓冲区与非直接缓冲区

    • 直接缓冲区:allocateDirect,直接在操作系统的内存中创建缓冲区,耗费资源,不易控制。

    • 非直接缓冲区:allocate,JVM内存中创建缓冲区

      		ByteBuffer direct = ByteBuffer.allocateDirect(1024);
              ByteBuffer noDirect = ByteBuffer.allocate(1024);
              System.out.println(direct.isDirect());
              System.out.println(noDirect.isDirect());		
      

    6、分散和聚集

    • 分散读取(Scattering Reads)是指从Channel 中读取的数据“分散”到多个Buffer 中。
    • 聚集写入(Gathering Writes)是指将多个Buffer 中的数据“聚集”到Channel。

    7、字符集

    • 编码
      • 字符串转换为字符数组的过程
    • 解码
      • 字符数组转换为字符串的过程
    		Map<String, Charset> map = Charset.availableCharsets();
            for (Map.Entry entry : map.entrySet()){
                System.out.println(entry.getKey() +":" + entry.getValue());
            }
      		Charset charset = Charset.forName("UTF-8");
            CharsetEncoder encoder = charset.newEncoder();
            CharsetDecoder decoder = charset.newDecoder();
    

8、NIO的非阻塞式网络通信

  • 传统的IO 流都是阻塞式的。也就是说,当一个线程调用read() 或write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。因此,在完成网络通信进行IO 操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降。
  • Java NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞IO 的空闲时间用于在其他通道上执行IO 操作,所以单独的线程可以管理多个输入和输出通道。因此,NIO 可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户端。