《Java NIO》:Channel and Buffer (通道和缓冲区)
从今天开始,自己将会了解下Java NIO的相关知识,以及会看下相关的类库源码。
和往常自己学习新知识之前,自己都会阅读网上的一些博文和资料,以使自己对这一块的知识有一个大致的了解,然后再按照自己感兴趣的点来研究一点点知识。关于Java NIO这一块的知识,也是如此。
关于Java NIO涉及到三个重要的概念:
1、Channel 通道
2、Buffer 缓冲区
3、Selector 选择器
在这篇文章的评论中对Java NIO 中的三个概念用一个比方来讲述,比较好理解,摘入如下:
其中Channel对应以前的流,Buffer不是什么新东西,Selector是因为NIO可以使用异步的非堵塞模式才加入的东西。
以前的流总是堵塞的,一个线程只要对它进行操作,其它操作就会被堵塞,也就相当于水管没有阀门,你伸手接水的时候,不管水到了没有,你就都只能耗在接水(流)上。
NIO的Channel的加入,相当于增加了水龙头(有阀门),虽然一个时刻也只能接一个水管的水,但依赖轮换策略,在水量不大的时候,各个水管里流出来的水,都可以得到妥善接纳,这个关键之处就是增加了一个接水工,也就是Selector,他负责协调,也就是看哪根水管有水了的话,在当前水管的水接到一定程度的时候,就切换一下:临时关上当前水龙头,试着打开另一个水龙头(看看有没有水)。
当其他人需要用水的时候,不是直接去接水,而是事前提了一个水桶给接水工,这个水桶就是Buffer。也就是,其他人虽然也可能要等,但不会在现场等,而是回家等,可以做其它事去,水接满了,接水工会通知他们。
这其实也是非常接近当前社会分工细化的现实,也是统分利用现有资源达到并发效果的一种很经济的手段,而不是动不动就来个并行处理,虽然那样是最简单的,但也是最浪费资源的方式。
上面的比方还是相当清晰的描述了Channel、Buffer和Selector的作用。
更多的关于Java NIO的学习资料,并发编程网上有关于Java NIO系列的教程,地址如下:http://ifeve.com/java-nio-all/。
本着学习的态度,自己也是跟着这一系列的文章进行学习、实验、看源码以及记录,以此来掌握Java NIO相关的知识。
这篇博文主要介绍下Channel和Buffer,以及写两个小Demo,让我们感性的认识一下这两个小东西。
Java NIO:Channel and Buffer (通道和缓冲区)
标准的IO基于字节流和字符流来进行操作的,而NIO是基于Channel and Buffer进行操作的,数据总是从通道读取到缓冲区中,从缓冲区中写入到通道中。
需要我们要牢记的是:数据总是从通道读取到缓冲区中,将缓冲区中的内容写到到通道中。
Channel 与 Buffer之间的交互图如下:
下面就先介绍下Channel,然后在介绍下Buffer。
Java NIO:Channel介绍
Java NIO的通道类似Java IO中的流。
Channel的实现
以下是Java NIO中最重要的通道的实现:
1、FileChannel:从文件中读写数据
2、DatagramChannel:能通过UDP读写网络中的数据。
3、SocketChannel:能通过TCP读写网络中的数据。
4、ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
下面先通过一个例子来感受下Channel和Buffer。
package com.wrh.channel;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class ChannelDemo {
//为简化代码逻辑,直接将异常抛出
public static void main(String[] args) throws IOException {
String path = "D:"+File.separator+"data.txt";
RandomAccessFile aFile = new RandomAccessFile(path,"rw");
FileChannel channel = aFile.getChannel();//得到管道
//借助一个Buffer来与Channel进行交互
ByteBuffer buffer = ByteBuffer.allocate(128);
int readByteLen;
while((readByteLen=channel.read(buffer))!=-1){
System.out.println("读取到buffer中的数据长度为:"+readByteLen);
System.out.println("内容如下:");
buffer.flip();//将Buffer从写模式切换到读模式
while(buffer.hasRemaining()){
System.out.print(buffer.get());
}
buffer.clear();
System.out.println();//换行
}
aFile.close();
}
}
以上就是关于FileChannel和Buffer的一个小例子。
从上面的例子中,我们已经使用Buffer,使用Buffer读写数据一般遵循以下四个步骤
1、写入数据到Buffer
2、调用flip()方法
3、从Buffer中读取数据
4、调用clear()方法或者是compact()方法来清空Buffer中的内容
当向Buffer写入数据时,Buffer会记录下写了多少数据。一旦要读取数据,需要调用flip()方法将Buffer从写模式切换到读模式。在读模式下,可以读取之前写入到Buffer中的所有数据。
一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式清空缓冲区:调用clear()和compact()方法。但是这里要注意这两个函数的区别:clear()方法会清空整个缓冲区。compact()方法只会清除已经读过的数据。任何未读的数据都会被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。
Buffer有以下几种类型
ByteBuffer ShortBuffer IntBuffer LongBuffer FloatBuffer DoubleBuffer CharBuffer MappedByteBuffer
从上面可以看出,有8种基本数据类型中除boolean类型所对应的Buffer类型。换句话说,我们可以通过char,short,int,long,float,double类型来操作缓冲区的数据。
下面先看一个关于Buffer的例子。
package com.wrh.nio;
import java.nio.IntBuffer;
public class BufferDemo {
public static void main(String[] args) {
//开辟一段buff空间
int cap = 10;
IntBuffer buffer = IntBuffer.allocate(cap);
//往buffer中添加数据
for(int i=0;i<cap;i++){
buffer.put(i*i);
}
System.out.println("buffer中的内容如下:");
/*
* 调用flip()方法切换到读模式。
* 如果没有buffer.flip();这句话,则buffer.hasRemaining()就为false,即下面的while循环就没有输出
* */
buffer.flip();
while(buffer.hasRemaining()){
System.out.print(buffer.get()+" ");
}
buffer.clear();//清除Buffer中的内容
}
}
在Buffer中,我们也可以采用for循环来读取Buffer中的数据。
for(int i=0;i<cap;i++){
System.out.print(buffer.get(i)+" ");
}
小结
以上就是关于Channel和Buffer的一点小介绍,以及写了两个小的Demo来感受下这两个的功能。下篇博文,我们将从源码的角度来分析下Buffer以及其中的几个子类的内部实现。
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。