java nio_buffer

IO流

在计算机中涉及到数据传输,使用的一定是IO流

同步和异步

同步:在一个时间段内,只有1个线程可以访问某个资源
异步:在一个时间段内,多个线程可以同时访问资源

阻塞和非阻塞

阻塞:当逻辑没有执行成功或者没有收到预期的结果时,就不在往下执行,而是等待,叫做阻塞。
例如BIO中的socket,其中的connect,write,read,服务器端的accept等方法都是阻塞的
非阻塞:不管逻辑取得的结果是啥都不做等待,继续往下执行

所以,同步不等于阻塞,异步也不等于非阻塞,两个是不同的东西

java中的IO分类

BIO:BlockingIO,同步阻塞式IO,传统IO都是阻塞式IO;同一时间只能一个线程操作流,并且如果没有读到数据或者没有写出数据,会hang住。
NIO: 新IO,或者NonBlockingIO,同步非阻塞式IO;NIO是同步的,保证线程安全,但是NIO也是非阻塞的,读取不到,连接不到,没有写入等都不会等待
AIO:AsynchronousIO,异步非阻塞式IO,jdk1.8提供。 在NIO的基础上做出改进,也叫NIO.2;AIO异步的,可以多个线程一起使用, 而且没有阻塞。 AIO也是效率最高的IO

BIO的缺点

1、阻塞式IO,只要读不到就会一直等,写数据时如果写不出去也会一直等。
2、因为阻塞,所以必须使用多线程。客户端每发起一次连接,服务器端就需要创建一个线程来处理客户端的这个连接。如果服务器端启动的线程数量太多,会导致服务器卡顿
3、无法解决无用连接的问题;如果客户端连接至服务器,不执行任务操作,只是在while(true)的话,会导致大量的无用连接,资源浪费
4、BIO只能用于单向传输,分为输入流和输出流。所以完成一次双向的读写需要创建多个对象。同样会浪费服务器资源。

如下图:服务器接受到一个客户端请求,必须利用子线程来处理这个请求
在这里插入图片描述
NIO解决了以上的四个缺点

NIO核心数据存储-Buffer

存储数据可以使用多种结构,变量,数组,链表等。
在NIO中,用于数据存储的就是Buffer,对数据进行 存储 (相当于一节火车,专门存数据的)

Buffer底层是也是数组,就有8中基本数据类型中的7中,提供了以下几种数据传输的容器:
ByteBuffer,ShortBuffer,IntBuffer,LongBuffer,DoubleBuffer,FloatBuffer,CharBuffer

关于buffer的几个重要位置属性

capacity:容量位。用于标记当前缓冲区的容量。
limit:限制位。用于标记操作位所能达到的最大下标。当操作位和限制位重合就表示所有的位置已经操作完。当缓冲区刚创建的时候,limit和capacity是重合的 。
position:操作位。等价于数组中的下标。读写后都会自动后移。无论以何种方式创建的缓冲区,position指向第0位 ;读到哪,写到哪,这个位置就在下一位
mark:标记位。mark的值默认为-1表示不启用

在这里插入图片描述

创建缓冲区

//直接分配一个字节数组,并且给定容量
ByteBuffer buffer = ByteBuffer.allocate(10);

向缓冲区中存入数据

// 添加数据,添加一个字节数组
buffer.put("abc".getBytes());
//添加一个字节
buffer.put((byte) 0);

从缓冲区取出数据

//取出position指向的字节
byte b1 = buffer.get();
//当需要发送的数据已知时,可以快速获取Buffer,此时buffer的position还是0
ByteBuffer buffer = ByteBuffer.wrap("hello big1910".getBytes());
//不再时1个字节1个字节的取出,直接获取Buffer底层的字节数组的地址
byte[] data = buffer.array();

"获取底层的字节数组后,需要注意有效数据的位置"

ByteBuffer buffer = ByteBuffer.allocate(100);
buffer.put("hello big1910".getBytes());
byte[] data = buffer.array();
System.out.println(data.length); //这里返回100
System.out.println(new String(data, 0, buffer.position()));
"或者"
buffer.flip();
System.out.println(new String(data, 0, buffer.limit()));

获取位置量

// 获取缓冲区的容量位
 System.out.println(buffer.capacity());
// 获取缓冲区的操作位
 System.out.println(buffer.position());
// 获取缓冲区的限制位
 System.out.println(buffer.limit()); 

设置位置量

//设置limit的位置为position的位置
buffer.limit(buffer.position());
// 设置position的位置为起始位置
buffer.position(0);

遍历缓冲区

在遍历缓冲区区之前,需要对Buffer进行翻转,因为存储数据结束后,position指向最后一个数据的下一位。
需要先将limit移动至position,然后再将position移动为0位,然后开始从position读取到limit

buffer.limit(buffer.position());
buffer.position(0);
while(buffer.position() < buffer.limit()){
	  byte b = buffer.get();
      System.out.println(b);
}

"等价于"
 buffer.flip(); //翻转缓冲区,设置limit,设置position
 while (buffer.hasRemaining()) { //等价于判断position是否小于limit
      byte b = buffer.get();
      System.out.println(b);
}

翻转,清空,重置,重绕

"翻转"
public final Buffer flip(){
limit = position;//设置limit到操作位
position = 0; //操作位重来
mark = -1; //翻转缓冲区,mark标记会被清除
return this;
}
"清空缓冲区数据"
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
"reset:重置缓冲区,重置mark到position这一段数据"
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
"rewind:重绕缓冲区(当数据需要重复读取时,不修改limit,只重置position)"
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}

#其他
1、多个线程同时操作缓冲区,会不会造成指针争抢呢?
不会,应为NIO是同步非阻塞,操作Buffer是同步的,保证了同一时间内,只有一个线程能够使用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值