[TOC]
## 第一章 缓冲区的使用
在NIO技术的缓冲区中,存在4个核心技术点,分别是:
❑capacity(容量)
❑limit(限制)
❑position(位置)
❑mark(标记)
![](https://img.kancloud.cn/86/80/8680a2d4dccdd5673e4c14b229ef9ff5_637x179.png)
这4个技术点之间值的大小关系如下:0≤mark≤position≤limit≤capacity。
由于ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer和ShortBuffer是抽象类,wrap()就相当于创建这些缓冲区的工厂方法。最终对应的类型分别为`java.io.HeapByteBuffer`、`java.io.HeapCharBuffer`、`java.io.HeapDoubleBuffe`等。
### limit
限制(limit)代表第一个不应该读取或写入元素的index,缓冲区的limit不能为负,并且limit不能大于其capacity。如果position大于新的limit,则将position设置为新的limit。如果mark已定义且大于新的limit,则丢弃该mark。
![image-20210501144736092](https://gitee.com/cowboy2014/cloud2020-config/raw/master//pictures/image-20210501144736092.png)
```java
public class BufferTest {
@Test
public void bufferLimitTest(){
char[] charArray = new char[]{'a','b','c','d','e'};
CharBuffer buffer = CharBuffer.wrap(charArray);
System.out.println("A capacity()=" + buffer.capacity() + ",limit="+buffer.limit());
buffer.limit(3);
System.out.println("B capacity()=" + buffer.capacity() + ",limit="+buffer.limit());
buffer.put(0,'o');
buffer.put(1,'p');
buffer.put(2,'q');
buffer.put(3,'r');//index == 3,第一个不可读不可写的索引
buffer.put(4,'s');
buffer.put(5,'t');
buffer.put(6,'u');
}
}
```
### position(位置)
什么是位置呢?它代表“下一个”要读取或写入元素的index(索引),缓冲区的position(位置)不能为负,并且position不能大于其limit。如果mark已定义且大于新的position,则丢弃该mark。
![image-20210501151228104](https://gitee.com/cowboy2014/cloud2020-config/raw/master//pictures/image-20210501151228104.png)
```java
@Test
public void bufferLimitTest(){
char[] charArray = new char[]{'a','b','c','d','e'};
CharBuffer buffer = CharBuffer.wrap(charArray);
System.out.println("A capacity()=" + buffer.capacity() + ",limit="+buffer.limit()+ ",position="+buffer.position());
buffer.limit(3);
System.out.println("B capacity()=" + buffer.capacity() + ",limit="+buffer.limit() + ",position="+buffer.position());
buffer.put(0,'o');
buffer.put(1,'p');
buffer.put(2,'q');
buffer.put(3,'r');//index == 3,第一个不可读不可写的索引
buffer.put(4,'s');
buffer.put(5,'t');
buffer.put(6,'u');
}
```
> 运行结果如下:
> A capacity()=5,limit=5,position=0
> B capacity()=5,limit=5,position=2
> a
> b
> Z
> d
> e
### mark(标记)
标记有什么作用呢?缓冲区的标记是一个索引,在调用reset()方法时,会将缓冲区的position位置重置为该索引。标记(mark)并不是必需的。定义mark时,不能将其定义为负数,并且不能让它大于position。
- 如果定义了mark,则在将position或limit调整为小于该mark的值时,该mark被丢弃,丢弃后mark的值是-1。
- 如果未定义mark,那么调用reset()方法将导致抛出`InvalidMarkException`异常。
简而言之,buffer的reset()方法,可以根据mark()的位置,把位置重置为mark()调用时的位置。
其他的一些关系:
- 如果position大于新的limit,则position的值就是新limit的值。
### 缓冲区操作
| 方法名 | 方法含义 | 用途|
| --- | --- | --- |
| clear() | position=0; limit=capacity; mark = null|还原缓冲区|
| flip() | limit=positon; position=0; | 先写后读|
| rewind() | position=0; mark =null| 重读、重写|
- clear(),还原缓冲区。还原缓冲区到初始的状态,包含将位置设置为0,将限制设置为容量,并丢弃标记,即“回到默认”。
- flip()。反转缓冲区。首先将限制设置为当前位置,然后将位置设置为0。为啥不叫做截取有效缓冲区呢?flip()常用在向缓冲区中写入一些数据后,下一步读取缓冲区中的数据之前调用,以改变limit与position的值。
- rewind(),重绕此缓冲区,将位置设置为0并丢弃标记。在重新读取、重新写入时可以使用。
## 二、缓冲区的内存分配
### 非直接缓冲区和直接缓冲区
#### 非直接缓冲区
![image-20210501153630472](https://gitee.com/cowboy2014/cloud2020-config/raw/master//pictures/image-20210501153630472.png)
通过ByteBuffer向硬盘存取数据时是需要将数据暂存在JVM的中间缓冲区,如果有频繁操作数据的情况发生,则在每次操作时都会将数据暂存在JVM的中间缓冲区,再交给ByteBuffer处理,这样做就大大降低软件对数据的吞吐量,提高内存占有率,造成软件运行效率降低,这就是非直接缓冲区保存数据的过程,所以非直接缓冲区的这个弊端就由直接缓冲区解决了。
#### 直接缓冲区
![image-20210501153705097](https://gitee.com/cowboy2014/cloud2020-config/raw/master//pictures/image-20210501153705097.png)
- 前言
- 第一部分 计算机网络与操作系统
- 大量的 TIME_WAIT 状态 TCP 连接,对业务有什么影响?怎么处理?
- 性能占用
- 第二部分 Java基础
- 2-1 JVM
- JVM整体结构
- 方法区
- JVM的生命周期
- 堆对象结构
- 垃圾回收
- 调优案例
- 类加载机制
- 执行引擎
- 类文件结构
- 2-2 多线程
- 线程状态
- 锁与阻塞
- 悲观锁与乐观锁
- 阻塞队列
- ConcurrentHashMap
- 线程池
- 线程框架
- 彻底搞懂AQS
- 2-3 Spring框架基础
- Spring注解
- Spring IoC 和 AOP 的理解
- Spring工作原理
- 2-4 集合框架
- 死磕HashMap
- 第三部分 高级编程
- Socket与NIO
- 缓冲区
- Bybuffer
- BIO、NIO、AIO
- Netty的工作原理
- Netty高性能原因
- Rabbitmq
- mq消息可靠性是怎么保障的?
- 认证授权
- 第四部分 数据存储
- 第1章 mysql篇
- MySQL主从一致性
- Mysql的数据组织方式
- Mysql性能优化
- 数据库中的乐观锁与悲观锁
- 深度分页
- 从一条SQL语句看Mysql的工作流程
- 第2章 Redis
- Redis缓存
- redis key过期策略
- 数据持久化
- 基于Redis分布式锁的实现
- Redis高可用
- 第3章 Elasticsearch
- 全文查询为什么快
- battle with mysql
- 第五部分 数据结构与算法
- 常见算法题
- 基于数组实现的一个队列
- 第六部分 真实面试案例
- 初级开发面试材料
- 答案部分
- 现场编码
- 第七部分 面试官角度
- 第八部分 计算机基础
- 第九部分 微服务
- OpenFeign工作原理