本系列博客转载自:海纳的知乎专栏
https://www.zhihu.com/people/hinus/activities
JAVA NIO系列,本人补充一些“作业”
nio(1):buffer、
https://zhuanlan.zhihu.com/p/27296046
作业:查看 clear, rewind, remaining, isRemaining等方法的实现,并理解。
本节课是小密圈《进击的Java新人》第十六周第一节课。从这节课开始,我会连续地介绍一下Java中的nio库。
nio中包含了很多东西,我个人认为最核心的是selector,那里我会使用大量的篇幅去介绍。但在那之前,我们还是从最简单的东西入手。今天只讲一下buffer。
在没有使用nio之前,我们只能自己维护一个byte数组或者是char数组来进行批量读写,或者使用BufferedReader,BufferedInputStream来做读写缓冲。在nio里,就可以使用buffer了。学习使用这个buffer要有点耐心,彻底了解它的机制再去用,这玩意的设计不是很友好。我在第一次用的时候,也是发现它的接口各种不符合期望,只好沉下心来一点点把它的原理搞清楚了才会用的。所以,学习这一课,一定不能焦躁。
缓冲区基础
本质上,缓冲区是就是一个数组。所有的缓冲区都具有四个属性来提供关于其所包含的数组的信息。它们是:
容量(Capacity) 缓冲区能够容纳的数据元素的最大数量。容量在缓冲区创建时被设定,并且永远不能被改变。
上界(Limit) 缓冲区里的数据的总数,代表了当前缓冲区中一共有多少数据。
位置(Position) 下一个要被读或写的元素的位置。Position会自动由相应的 get( )和 put( )函数更新。
标记(Mark) 一个备忘位置。用于记录上一次读写的位置。一会儿,我会通过reset方法来说明这个属性的含义。
我们以字节缓冲区为例,ByteBuffer是一个抽象类,不能直接通过 new 语句来创建,只能通过一个static方法 allocate 来创建:
ByteBuffer byteBuffer = ByteBuffer.allocate(256);
以上的语句可以创建一个大小为256字节的ByteBuffer,此时,mark = -1, pos = 0, limit = 256, capacity = 256。capacity在初始化的时候确定了,运行时就不会再变化了,而另外三个变量是随着程序的执行而不断变化的。
缓冲区的存取
缓冲区用于存取的方法定义主要是put , get。
put 方法有多种重载,我们看其中一个:
public ByteBuffer put(byte x) {
hb[ix(nextPutIndex())] = x;
return this;
}
final int nextPutIndex() { // package-private
if (position >= limit)
throw new BufferOverflowException();
return position++;
}
这个方法是把一个byte变量 x 放到缓冲区中去。position会加1。再来看一下get方法,也是从position的位置去取缓冲区中的一个字节:
public byte get() {
return hb[ix(nextGetIndex())];
}
final int nextGetIndex() { // package-private
if (position >= limit)
throw new BufferUnderflowException();
return position++;
}
那比如,我要是想在一个Buffer中放入了数据,然后想从中读取的话,就要把position调到我想读的那个位置才行。为此,ByteBuffer上定义了一个方法:
public final Buffer position(int newPosition) {
if ((newPosition > limit) || (newPosition < 0))
throw new IllegalArgumentException();
position = newPosition;
if (mark > position) mark = -1;
return this;
}
这里面用到了limit,想一下上面的定义,limit代表可写或者可读的总数。一个新创建的bytebuffer,它可写的总数就是它的capacity。如果写入了一些数据以后,想从头开始读的话,这时候的limit应该就是当前ByteBuffer中数据的总长度。下面的这个图比较直观地说明了这个问题:
为了达到从写数据的情况变成读数据的情况,还需要修改limit,这就要用到limit方法:
public final Buffer limit(int newLimit) {
if ((newLimit > capacity) || (newLimit < 0))
throw new IllegalArgumentException();
limit = newLimit;
if (position > limit) position = limit;
if (mark > limit) mark = -1;
return this;
}
我们可以这样写,就把byteBuffer从读变成写了:
(转注:这里应该是写buffer模式切换到读buffer模式)
byteBuffer.limit(byteBuffer.position())
byteBuffer.position(0);
当然,由于这个操作非常频繁,jdk就为我们封装了一个这样的方法,叫做flip:
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
使用这个反转方法,思路一定要清晰,稍有不慎,就会带来莫名其妙的错误,比如,连续调用flip会对ByteBuffer有什么样的影响呢?这其实会使得Buffer的limit变成0,从而既不能读也不能写了。
limit的设计确实可以加速数据溢出情况的检查,但是造成使用上和理解上的困难,我还是觉得得不偿失。我一直觉得limit这个设计很蠢(个人意见,如果有误,请各位指正)。
缓冲区标记
今天最后一个内容,是讲一下mark的作用。在理解了position的作用以后,mark就很容易理解了,它就是记住当前的位置用的:
public final Buffer mark() {
mark = position;
return this;
}
我们在调用过mark以后,再进行缓冲区的读写操作,position就会发生变化,为了再回到当初的位置,我们可以调用reset方法恢复position的值:
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
好了。今天的内容就这些了。作业:
查看 clear, rewind, remaining, isRemaining等方法的实现,并理解。
==========================================================================
下面开始做作业:
以上方法都来自java.nio.Buffer抽象类
clear 方法作用是把缓冲区的标识重置,里边的内容并不真正清空。
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
rewind方法用于反复读取某一段缓冲区,比如:
out.write(buf); // Write remaining data
buf.rewind(); // Rewind buffer
buf.get(array);
将缓冲区内容写入通道后,position的位置从0变到了写入字节数的位置,然后调用buf.rewind();后,position=0,mark=-1;表示这块缓冲区你又可以读去了(向channel中写)。和clear的唯一区别是limit位置不变(rewind方法要求limit已经被正确设定了),clear会将limit位置更新为容量。
源代码:
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
remaining方法用于得到缓冲区剩余多少元素未处理,返回的是缓冲中limit-position的值。
public final int remaining() {
return limit - position;
}
hasRemaining方法
(我的jdk1.7是hasRemaining,没有isRemaining,原作者应该是笔误)
该方法用于判断缓冲中是否有元素未处理。如果limit>position表示还有元素,否则表示都已经处理过了。
public final boolean hasRemaining() {
return position < limit;
}
除了上面的这些方法还有一个比较常用的方法compact()
该方法的作用是未读取过得数据拷贝到缓冲区的最开始。然后position设置成这些元素的个数的位置,用于后边写缓冲区。经常应用的场景是,一个缓冲区,读取了一部分数据之后呢,又想往这个缓冲区写数据,为了不破坏未读取的数据,需要前移未读取数据,在这些数据后面再写入新数据。
这个方法在ByteBuffer是抽象方法,在其子类中实现。
HeapByteBuffer.java
public ByteBuffer compact() {
//本地方法,用于拷贝数组,可以看出将剩余元素拷贝到自身开始位置
System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
//position设置成剩余元素个数位置
position(remaining());
//可写的范围,设置成容量
limit(capacity());
//是上一次的读写位置mark无效。
discardMark();
return this;
}
第一节课的作业做完了,留着以后复习。
下一篇:
http://zxp209.iteye.com/admin/blogs/2396809
分享到:
相关推荐
赠送jar包:xnio-nio-3.8.0.Final.jar; 赠送原API文档:xnio-nio-3.8.0.Final-javadoc.jar; 赠送源代码:xnio-nio-3.8.0.Final-sources.jar; 赠送Maven依赖信息文件:xnio-nio-3.8.0.Final.pom; 包含翻译后的API...
Java-NIO非阻塞服务器示例 本资源主要讲解了Java-NIO非阻塞服务器的示例,通过使用Java-NIO包来实现非阻塞的服务器端模式。下面是从代码中提取的知识点: 一、Java-NIO包简介 Java-NIO(New I/O)包是Java 1.4...
本示例"JAVA-NIO-DEMO"提供了关于Java NIO的实际应用,通过Anontion(注解)、Applet(小程序)和NIO的Demo,帮助开发者更深入地理解和掌握这些概念。 首先,让我们深入了解Java NIO。NIO的核心组件包括: 1. **...
Java NIO (Non-blocking Input/Output) 是Java平台中用于高效处理I/O操作的一种机制,它与传统的IO模型( Blocking I/O)相比,提供了更高级别的抽象,允许应用程序以非阻塞的方式读写数据,提高了并发性能。...
赠送jar包:httpcore-nio-4.4.10.jar; 赠送原API文档:httpcore-nio-4.4.10-javadoc.jar; 赠送源代码:httpcore-nio-4.4.10-sources.jar; 赠送Maven依赖信息文件:httpcore-nio-4.4.10.pom; 包含翻译后的API文档...
基于java的开发源码-NIO网络框架 xSocket.zip 基于java的开发源码-NIO网络框架 xSocket.zip 基于java的开发源码-NIO网络框架 xSocket.zip 基于java的开发源码-NIO网络框架 xSocket.zip 基于java的开发源码-NIO网络...
赠送jar包:xnio-nio-3.8.4.Final.jar; 赠送原API文档:xnio-nio-3.8.4.Final-javadoc.jar; 赠送源代码:xnio-nio-3.8.4.Final-sources.jar; 赠送Maven依赖信息文件:xnio-nio-3.8.4.Final.pom; 包含翻译后的API...
1. **NIO基础** - **通道(Channels)**:NIO中的通道类似于流,但它们是双向的,可以读写数据。常见的通道类有FileChannel、SocketChannel和ServerSocketChannel等。 - **缓冲区(Buffers)**:缓冲区是数据的...
《深入解析httpcore-nio-4.3.jar:构建高性能的Java非阻塞网络通信》 在Java网络编程中,高效、稳定且可扩展的通信框架至关重要。Apache HttpComponents项目中的HttpCore NIO模块(httpcore-nio)就是这样一个框架...
赠送jar包:httpcore-nio-4.4.10.jar; 赠送原API文档:httpcore-nio-4.4.10-javadoc.jar; 赠送源代码:httpcore-nio-4.4.10-sources.jar; 赠送Maven依赖信息文件:httpcore-nio-4.4.10.pom; 包含翻译后的API文档...
赠送jar包:httpcore-nio-4.4.5.jar; 赠送原API文档:httpcore-nio-4.4.5-javadoc.jar; 赠送源代码:httpcore-nio-4.4.5-sources.jar; 赠送Maven依赖信息文件:httpcore-nio-4.4.5.pom; 包含翻译后的API文档:...
赠送jar包:xnio-nio-3.8.4.Final.jar; 赠送原API文档:xnio-nio-3.8.4.Final-javadoc.jar; 赠送源代码:xnio-nio-3.8.4.Final-sources.jar; 赠送Maven依赖信息文件:xnio-nio-3.8.4.Final.pom; 包含翻译后的API...
Java NIO(Non-blocking Input/Output)是一种在Java中处理I/O操作的新方式,相比于传统的BIO( Blocking I/O),NIO提供...通过理解和实践"java-NIO-demo",你将能够更好地掌握NIO的精髓,并在实际项目中发挥其优势。
赠送jar包:xnio-nio-3.8.0.Final.jar; 赠送原API文档:xnio-nio-3.8.0.Final-javadoc.jar; 赠送源代码:xnio-nio-3.8.0.Final-sources.jar; 赠送Maven依赖信息文件:xnio-nio-3.8.0.Final.pom; 包含翻译后的API...
赠送jar包:httpcore-nio-4.4.6.jar; 赠送原API文档:httpcore-nio-4.4.6-javadoc.jar; 赠送源代码:httpcore-nio-4.4.6-sources.jar; 赠送Maven依赖信息文件:httpcore-nio-4.4.6.pom; 包含翻译后的API文档:...
赠送jar包:httpcore-nio-4.4.14.jar; 赠送原API文档:httpcore-nio-4.4.14-javadoc.jar; 赠送源代码:httpcore-nio-4.4.14-sources.jar; 赠送Maven依赖信息文件:httpcore-nio-4.4.14.pom; 包含翻译后的API文档...
### Java-NIO2教程知识点详解 #### I/O发展简史 - **JDK1.0-1.3**: 在此期间,Java的I/O模型主要依赖于传统的阻塞I/O方式,这种模式下,应用程序在等待I/O操作完成时无法执行其他任务,导致效率低下。此外,当时的...
**JAVA-NIO程序设计完整实例** Java NIO(New IO)是Java 1.4引入的一个新特性,它为Java提供了非阻塞I/O操作的能力,使得Java在处理I/O时更加高效。NIO与传统的BIO(Blocking I/O)模型相比,其核心在于它允许程序...