Java NIO(非阻塞IO)图文详细解析。源码分析

本文详细介绍了Java NIO(非阻塞IO)的概念,对比了IO与NIO的区别,并重点讲解了通道、缓冲区的使用,包括缓冲区的方法、核心属性以及直接缓冲区和非直接缓冲区。此外,还阐述了NIO的非阻塞式网络通信,包括使用选择器、通道和缓冲区进行网络通信,并展示了如何用NIO实现简单的聊天室功能。
摘要由CSDN通过智能技术生成

Java NIO

概念

Java NIO(New IO),No Blocking IO 非阻塞IO,是从Java1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的,基于通道的IO操作。NIO将以更加高效的方式进行文件读写操作

IO和NIO的区别

IO NIO
面向流(Stream Oriented) 面向缓冲区(Buffer Oriented)
阻塞IO(Blocking IO) 非阻塞IO(Non Blocking IO)
选择器(Selectors)

image-20200327143758859

  • 传统的IO是单向的
    • 也就是需要建立输入流和输出流两个管道,数据的流动只能是单向的

image-20200327144423143

  • NIO是双向的

    • 里面的缓存区是可以双向传输的
  • NIO里面引入的通道的概念

    • 通道可以理解为我们生活中的铁路,它是用于源地址和目的地址连接的
    • 如果需要实际传输的话,那么需要依赖里面的缓冲区
    • 通道负责连接,缓冲区负责传输

通道和缓冲区

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

简而言之:Channel负责传输,Buffer负责存储

缓冲区 Buffer

在Java NIO中负责数据的存取。缓冲区就是数组。用于存储不同类型的数据根据数据类型不同,提供相同类型的缓冲区(除了Boolean)

  • ByteBuffer:字节缓冲区(最常用的)
  • CharBuffer
  • ShortBuffer
  • IntBuffer
  • LongBuffer
  • FloatBuffer
  • DoubleBuffer

缓冲区中的方法

上面缓冲区的管理方式几乎一致, 通过 allocate() 获取缓冲区

缓冲区存取数据的两个核心方法

  • put():存入数据到缓冲区中
  • get():获取缓冲区中的数据
  • hasRemaining():判断缓冲区是否还有剩余的数据
  • remaining():获取缓冲区还有多少剩余数据
  • mark():标记postion的位置
  • reset():恢复到刚标记的地方

缓冲区中的核心属性

image-20200327150236836

  • capacity:容量,表示缓冲区中最大存储数据的容量,一旦申明不可改变。
  • limit:界限,表示缓冲区中的可以操作数据的大小。(limit 后数据不能进行读写)
  • position:位置,表示缓冲区中正在操作的位置
  • mark:标记,表示记录当前 position 的位置,可以通过reset() 恢复到 mark的位置

最后它们之间的关系是:0 <= mark <= position <= limit <= capacity

相关操作

我们首先操作一个大小为1024字节的缓冲区ByteBuffer

// 分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println("初始化");
System.out.println("position:" + buf.position());
System.out.println("limit:" + buf.limit());
System.out.println("capacity:" + buf.capacity());

然后在传入字符串到缓冲区

// 存入数据到缓冲区
String str = "abcde";
buf.put(str.getBytes());

System.out.println("存入数据");
System.out.println("position:" + buf.position());
System.out.println("limit:" + buf.limit());
System.out.println("capacity:" + buf.capacity());

然后开始读取数据,在读取数据前,我们需要使用flip切换到读取数据模式

// 切换读取数据模式
buf.flip();
System.out.println("切换读取数据模式");
System.out.println("position:" + buf.position());
System.out.println("limit:" + buf.limit());
System.out.println("capacity:" + buf.capacity());

然后在进行读取操作,我们需要创建一个byte[] 数组,将需要读取出来的数据放进去

// 开始读取数据
System.out.println("开始读取数据");
byte[] dst = new byte[buf.limit()];
buf.get(dst);
System.out.println(new String(dst, 0, dst.length));

下面这个图,是我们在执行各个步骤时, position,limit,capacity的变换

image-20200327150814326

完整代码:

/**
 * 缓冲区:Buffer
 * 在Java NIO中负责数据的存取。缓冲区就是数组。用于存储不同类型的数据
 * 根据数据类型不同,提供相同类型的缓冲区(除了Boolean)
 * ByteBuffer
 * CharBuffer
 * @author: 陌溪
 * @create: 2020-03-27-14:48
 */
public class BufferDemo {
   

    public static void main(String[] args) {
   
        // 分配一个指定大小的缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);
        System.out.println("初始化");
        System.out.println("position:" + buf.position());
        System.out.println("limit:" + buf.limit());
        System.out.println("capacity:" + buf.capacity());

        // 存入数据到缓冲区
        String str = "abcde";
        buf.put(str.getBytes());
        System.out.println("存入数据");
        System.out.println("position:" + buf.position());
        System.out.println("limit:" + buf.limit());
        System.out.println("capacity:" + buf.capacity());

        // 切换读取数据模式
        buf.flip();
        System.out.println("切换读取数据模式");
        System.out.println("position:" + buf.position());
        System.out.println("limit:" + buf.limit());
        System.out.println("capacity:" + buf.capacity());

        // 开始读取数据
        System.out.println("开始读取数据");
        byte[] dst = new byte[buf.limit()];
        buf.get(dst);
        System.out.println(new String(dst, 0, dst.length));

        System.out.println("数据读取完毕");
        System.out.println("position:" + buf.position());
        System.out.println("limit:" + buf.limit());
        System.out.println("capacity:" + buf.capacity());

        // rewind():表示重复读
        buf.rewind();
        System.out.println("rewind");
        System.out.println("position:" + buf.position());
        System.out.println("limit:" + buf.limit());
        System.out.println("capacity:" + buf.capacity());

        // clear():清空缓冲区,但是缓冲区中的数据仍然存储,但是处于被遗忘状态
        buf.clear();
        System.out.println("clear");
        System.out.println("position:" + buf.position
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值