Java中的NIO

知识储备(Java IO)

在这里插入图片描述

NIO概述

1. 定义

  • Java NIO,即Java New IO(Java新IO)。
  • 是一种同步非阻塞的IO模型。
  • 自JDK1.4起,引入的一种基于通道和缓冲区的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在Java 堆的 DirectByteBuffer 对象作为这块内存的引用进行操作,避免了在 Java 堆和 Native堆中来回复制数据。

2. 作用

  • 提供了与标准IO不同的IO工作方式
  • 可替代 标准Java IO 的IO API

3. 新特性

在这里插入图片描述

4. 核心组件

  • 缓冲区(Buffer)
  • 通 道(Channel)
  • 选择器(Selector)

Buffer

1. 定义

 Java NIO数据读/写的中转地(一块连续的内存块)。从内部结构上看,它就像一个数组,可以保存多个类型相同的数据。

2. 作用

数据缓存

3. 特点

适用于所有基本数据类型(布尔除外)

4. 使用

1)给Buffer分配空间

例如:以字节为单位,创建一个ByteBuffer对象并且指定内存大小:

ByteBuffer buffer = ByteBuffer.allocate(1024);

除了ByteBuffer外,对应于其他基本数据类型(布尔除外)都有相应的Buffer类:CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer,DoubleBuffer。区别在于:各子管理的数据类型不一样。

2)向Buffer中写入数据

  • 数据从Channel到Buffer:channel.read(buffer);
  • 数据从client到Buffer:buffer.put(……);

3)从Buffer中读取数据

  • 数据从Buffer到Channel:channel.write(buffer);
  • 数据从Buffer到Server:buffer.get(……);

Buffer中重要方法:

  • clear():为再次向Buffer中装入数据做好准备,清空整个缓冲区。
  • compact():只清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。
  • flip():为从Buffer中取出数据做好准备,即将Buffer从写模式切换到读模式。

Buffer中的三个重要属性

  • capacity:作为一个内存块,Buffer的固定大小值。只能往这里写capacity个基本数据类型的数据(布尔除外)。当Buffer满了,需要将其清空才能继续往里写数据。
  • position:在写数据到Buffer中时,position标识表示当前的位置,初始值为0。当将数据写到Buffer中后,position会向前移动到下一个可插入数据的Buffer单元。position最大可为-1。当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。
  • limit:在写模式下,limit表示最多能往Buffer中写的数据量,limit等于capacity;在读模式下,limit表示最多能读到的数据量,此时,limit会被设置成写模式下的position值。

position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式,capacity的含义总是一样的。

在这里插入图片描述
Buffer的使用

 public static void main(String[] args) {
        //1.创建Buffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        System.out.println("capacity:"+byteBuffer.capacity()+" position:"+byteBuffer.position()+" limit:"+byteBuffer.limit());
        //2.向Buffer中写入数据
        byte b1 = 10;
        byte b2 = 20;
       byteBuffer.put(b1);
       byteBuffer.put(b2);
       System.out.println("加入二个元素后--");
        System.out.println("capacity:"+byteBuffer.capacity()+" position:"+byteBuffer.position()+" limit:"+byteBuffer.limit());
      //3.调用flip()方法
        byteBuffer.flip();
        System.out.println("执行flip()方法后--");
        System.out.println("capacity:"+byteBuffer.capacity()+" position:"+byteBuffer.position()+" limit:"+byteBuffer.limit());

       //4.取出元素
        System.out.println("第一个元素:"+byteBuffer.get());

        //5.调用clear()方法
        byteBuffer.clear();
        System.out.println("调用clear()方法后--");
        System.out.println("capacity:"+byteBuffer.capacity()+" position:"+byteBuffer.position()+" limit:"+byteBuffer.limit());
    }

Channel

1. 定义

Java NIO的数据源头或者目的地,是缓冲区对象的唯一接口。

2. 作用

  • 从缓冲区读取数据
  • 向缓冲区写数据

3.特点

  • 是一个双向读、写通道。既可以从通道中读取数据,又可以将数据写入通道。
  • 异步读、写。
  • 数据来源/流向是缓冲区。即通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。

4.使用

根据数据来源的不同而不同。(含文件IO、TCP、UDP等)

  • FileChannel 从文件中读写数据。
  • DatagramChannel 能通过UDP读写网络中的数据。
  • SocketChannel 能通过TCP读写网络中的数据。
  • ServerSocketChannel可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。

Channel的使用:

/*复制文件*/

 /*直接将FileChannel数据映射成ByteBuffer*/
    public static void main(String[] args) {
        File f = new File("E:\\temps\\FileFilterDemos\\aa.txt");

        try {
            //创建FileInputStream,以该文件输入流创建FileChannel
            FileChannel inChannel = new FileInputStream(f).getChannel();
            FileChannel outChannel = new FileOutputStream("E:\\temps\\FileFilterDemos\\temp1.txt").getChannel();

            //将FileChannel里的全部数据映射成ByteBuffer
            MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());
            //使用GBK的字符集来创建解码器
            Charset charset = Charset.forName("GBK");
            //直接将Buffer里面的数据直接输出
            outChannel.write(buffer);
            //调用Buffer的clear()方法,复原limit、position值
            buffer.clear();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Selector

1.定义

是NIO的核心,是channel的管理者。通过执行select()阻塞方法,监听是否有channel准备好,一旦有数据可读,此方法的返回值是SelectionKey的数量。

2. 作用

实现异步、非阻塞操作。

3.特点

  • 允许一个Selector管理/处理多个通道Channel。

  • 使用一个Selector线程检测1个或者多个通道上的事件(channel)时,事件驱动分发事件,而不需要为每个channel分配一个线程。

注意:事件驱动=事件到的时候出发,而不是同步监视事件。

4.Selector的使用

1)创建selector对象

Selector selector = Selector.open();

2) 向selector注册通道channel

channel.configureBlocking(false);
SelectionKey key = channel.register(selector, Selectionkey.OP_READ);

注意:

  • 与Selector一起使用时,Channel必须处于非阻塞模式下。这意味着不能将FileChannel与Selector一起使用,因为FileChannel不能切换到非阻塞模式。而套接字通道都可以。
  • register()方法的第二个参数是一个“interest集合”,意思是在通过Selector监听Channel时对什么事件感兴趣。可以监听四种不同类型的事件:
 Connect;Accept;Read;Write

用SelectionKey的四个常量来表示为:

SelectionKey.OP_CONNECT;
SelectionKey.OP_ACCEPT;
SelectionKey.OP_READ;
SelectionKey.OP_WRITE;

3) 调用Selector的select()方法
该方法会一直阻塞到某个注册的通道有事件就绪。一旦该方法返回,线程就可以处理这些事件。

int readChannel = selector.select();
  • select()阻塞到至少有一个通道在你注册的事件上就绪了。
  • select(long timeout)和select()一样,除了最长会阻塞timeout毫秒(参数)。
  • selectNow()不会阻塞,不管什么通道就绪都立刻返回(译者注:此方法执行非阻塞的选择操作。如果自从前一次选择操作后,没有通道变成可选择的,则此方法直接返回零)。

selectedKeys():通过调用selector的selectedKeys()方法,访问“已选择键集(selected key set)”中的就绪通道。

NIO与IO的区别

在这里插入图片描述
另附:java NIO、AIO、BIO的区别

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值