NIO的缓冲区、通道、选择器关系理解
Buffer的数据存取
一个用于特定基本数据类行的容器。有java.nio包定义的,所有缓冲区都是抽象类Buffer的子类。
Java NIO中的Buffer主要用于与NIO通道进行交互,数据是从通道读入到缓冲区,从缓冲区写入通道中的。
Buffer就像一个数组,可以保存多个相同类型的数据。根据类型不同(boolean除外),有以下Buffer常用子类:ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer
Buffer的概述
1)容量(capacity):表示Buffer最大数据容量,缓冲区容量不能为负,并且建立后不能修改。
2)限制(limit):第一个不应该读取或者写入的数据的索引,即位于limit后的数据不可以读写。缓冲区的限制不能为负,并且不能大于其容量(capacity)。
3)位置(position):下一个要读取或写入的数据的索引。缓冲区的位置不能为负,并且不能大于其限制(limit)。
4)标记(mark)与重置(reset):标记是一个索引,通过Buffer中的mark()方法指定Buffer中一个特定的position,之后可以通过调用reset()方法恢复到这个position。
public class Test {
public static void main(String[] args) {
// 1.指定缓冲区大小1024
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println("--------------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
// 2.向缓冲区存放5个数据
buf.put("abcd1".getBytes());
System.out.println("--------------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
// 3.开启读模式
buf.flip();
System.out.println("----------开启读模式...----------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
byte[] bytes = new byte[buf.limit()];
buf.get(bytes);
System.out.println(new String(bytes, 0, bytes.length));
System.out.println("----------重复读模式...----------");
// 4.开启重复读模式
buf.rewind();
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
byte[] bytes2 = new byte[buf.limit()];
buf.get(bytes2);
System.out.println(new String(bytes2, 0, bytes2.length));
// 5.clean 清空缓冲区 数据依然存在,只不过数据被遗忘
System.out.println("----------清空缓冲区...----------");
buf.clear();
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
System.out.println((char)buf.get());
}
}
- make与rest用法
public class Test01 {
public static void main(String[] args) {
ByteBuffer buf = ByteBuffer.allocate(1024);
String str = "abcd1";
buf.put(str.getBytes());
// 开启读取模式
buf.flip();
byte[] dst = new byte[buf.limit()];
buf.get(dst, 0, 2);
buf.mark();
System.out.println(new String(dst, 0, 2));
System.out.println(buf.position());
buf.get(dst, 2, 2);
System.out.println(new String(dst, 2, 2));
System.out.println(buf.position());
buf.reset();
System.out.println("重置恢复到mark位置..");
System.out.println(buf.position());
}
}
通道Channel
通道可以同时进行读写,而流只能读或者只能写
通道可以实现异步读写数据
通道可以从缓冲读数据,也可以写数据到缓冲:
- 分散读取与聚集写入
分散读取:将通道中的数据分散到多个缓冲区中

聚集写入:将多个缓冲区的数据聚集到通道中

直接缓冲区与非直接缓冲区别
- 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中

// 1.利用通道完成文件的复制(非直接缓冲区)
static public void test1() throws IOException { // 4400
long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("e://1.jpg");
FileOutputStream fos = new FileOutputStream("e://2.jpg");
// ①获取通道
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel();
// ②分配指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
while (inChannel.read(buf) != -1) {
buf.flip();// 切换为读取数据
// ③将缓冲区中的数据写入通道中
outChannel.write(buf);
buf.clear();
}
outChannel.close();
inChannel.close();
fos.close();
fis.close();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
- 直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率

// 使用直接缓冲区完成文件的复制(内存映射文件)
static public void test2() throws IOException {
long start = System.currentTimeMillis();
FileChannel inChannel = FileChannel.open(Paths.get("e://1.jpg"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("e://2.jpg"), StandardOpenOption.WRITE,
StandardOpenOption.READ, StandardOpenOption.CREATE);
// 内存映射文件
MappedByteBuffer inMappedByteBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outMappedByteBuffer = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
// 直接对缓冲区进行数据的读写操作
byte[] dsf = new byte[inMappedByteBuf.limit()];
inMappedByteBuf.get(dsf);
outMappedByteBuffer.put(dsf);
inChannel.close();
outChannel.close();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
Selector
一个组件,可以检测多个NIO channel,看看读或者写事件是否就绪。
多个Channel以事件的方式可以注册到同一个Selector,从而达到用一个线程处理多个请求成为可能。

非阻塞IO数据准备就绪之后,由选择器发通知给服务器端,数据在准备之前服务器无需等待

NIO的缓冲区、通道、选择器关系理解的更多相关文章
- Java NIO之Selector(选择器)
历史回顾: Java NIO 概览 Java NIO 之 Buffer(缓冲区) Java NIO 之 Channel(通道) 其他高赞文章: 面试中关于Redis的问题看这篇就够了 一文轻松搞懂re ...
- java输入输出 -- java NIO之文件通道
一.简介 通道是 Java NIO 的核心内容之一,在使用上,通道需和缓存类(ByteBuffer)配合完成读写等操作.与传统的流式 IO 中数据单向流动不同,通道中的数据可以双向流动.通道既可以读, ...
- 类之间关系理解:组合>聚合>关联>依赖;实现,继承
类之间关系理解:组合>聚合>关联>依赖:实现,继承 1. 从类之间的关系来看,不外乎以下几种 组合>聚合>关联>依赖:实现,继承 且可以分为以下两类: (1)实现, ...
- [转]Shared——React Native与原生关系理解与对比
零.关系理解 这个是我对RN和原生关系的理解.简单解释下这个图. RN js编写完业务代码后,通过react-native bundle命令,将代码分别编译成一个index.ios.bundle和in ...
- go语言从例子开始之Example26.通道选择器
Go 的通道选择器 让你可以同时等待多个通道操作.Go 协程和通道以及选择器的结合是 Go 的一个强大特性. Example: package main import "time" ...
- 027_go语言中的通道选择器
代码演示 package main import "fmt" import "time" func main() { c1 := make(chan strin ...
- nio之缓冲区(Buffer)理解
一.缓冲区简介 Nio中的 Buffer 是用于存储特定基础类型的一个容器.为了能熟练的使用 Nio中的各种 Buffer , 我们需要理解 Buffer 中的 三个重要 的属性. 1. capaci ...
- NIO之缓冲区
NIO引入了三个概念: Buffer 缓冲区 Channel 通道 selector 选择器 1.java.io优化建议 操作系统与Java基于流的I/O模型有些不匹配.操作系统要移动的是大块数据(缓 ...
- Java NIO(六)选择器
前言 Selector选择器是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件.这样使得一个单独的线程可以管理多个Channel,从而管理多个网络连接.选择 ...
随机推荐
- spring util包 StringUtils工具类中的isEmpty() 方法解析
今天在公司看到同事写的代码,无意发现在判断字符串类型时,使用的是StringUtils工具类中的isEmpty()去判断如下所示 @RequestMapping(value = "/pub/ ...
- Centos7 yum安装OpenLDAP(普通用户可以更改密码)
环境 系统版本:centos7.4 openldap版本2.4 安装和配置 安装并启动服务 安装: yum install openldap openldap-servers openldap-cli ...
- [CSP-S模拟测试]:老司机的狂欢(LIS+LCA)
题目背景 光阴荏苒.不过,两个人还在,两支车队还在,熟悉的道路.熟悉的风景,也都还在.只是,这一次,没有了你死我活的博弈,似乎和谐了许多.然而在机房是不允许游戏的,所以班长$XZY$对游戏界面进行了降 ...
- Wowza 4.5 修改 manager 端口号
//编辑下面的文件, 搜索8088 有两处,改为想要的端口号即可 vim /usr/local/WowzaStreamingEngine/manager/bin/startmgr.sh // 重启服务 ...
- ajax传递json参数
var pros = []; for(var i = 1; i <= 2; i++) { var obj = {}; obj.id = i; obj.age = i*20; pros = pro ...
- LeetCode 47——全排列 II
1. 题目 2. 解答 在 LeetCode 46--全排列 中我们已经知道,全排列其实就是先确定某一个位置的元素,然后余下就是一个子问题.在那个问题中,数据没有重复,所以数据中的任意元素都可以放在最 ...
- Delphi XE2 之 FireMonkey 入门(23) - 数据绑定: TBindingsList: TBindExpression
准备用 TBindingsList 重做上一个例子. 可以先把 TBindingsList 理解为是一组绑定表达式(TBindExpression)的集合;官方应该是提倡在设计时完成 TBindExp ...
- 16/7/8_PHP-字符串介绍
不知道为什么慕课网还这个都要介绍.不过还是一个新的知识点. PHP开发中,我们遇到最多的可能就是字符串. 字符串变量用于包含字符串的值. 一个字符串 通过下面的3种方法来定义: 1.单引号2.双引号3 ...
- Learn Python the hard way, ex45 对象、类、以及从属关系
#!/usr/bin/python #coding:utf-8 # animal is-a object(yes,sort of sonfusing)look at the extra credit ...
- mooc-IDEA 高效定位代码--004
十.IntelliJ IDEA -高效定位代码-精准搜索 1.快速定位类:Navigate->Class... [Ctrl+N] 2.文件:Navigate->File.. [Ct ...