Q: buffer调用flip()方法从写模式切换到读模式时,position会变成多少?

A: 变为0。

ByteBuffer buf = ByteBuffer.allocate(1024);

// 数据读到buf中,并返回数量,每次最多读1024个

int byteRead = fileChannel.read(buf);

// 输出byteRead的数量,最多为1024

System.out.println(“position=” + buf.position()+“, byteRead=” + byteRead);

buf.flip();

// 切换到读模式了,输出0

System.out.println(“position=” + buf.position());

buffer拥有1个limit属性。 写模式下,buffer的limit就是buffer的capacity。

Q: 当buffer从写模式切换到读模式时,limit为多少?

A: 每次切换前都要调用flip(),切换后,limit为写模式中的position。

int byteRead = fileChannel.read(buf);

// 输出1024

System.out.println(“limit=” + buf.limit() + “,postion=” + buf.position());

System.out.println(“切换到读模式”);

buf.flip();

// 输出byteRead数量

System.out.println(“limit=” + buf.limit());

结果如下

Q: 向buf缓冲区写数据的方式有哪些?

A:

int byteRead = fileChannel.read(buf);

从通道中读数据到buf中, 即相当于向buf缓冲区中写数据。

buf.putChar(‘a’);

手动向buf中写入字符a, postion加1。

Q: 从buf缓冲区读数据的方式有哪些?

int bytesWrite = fileChannel.write(buf)

buf中的数据写入到管道,即相当于fileChannel读取buf中的数据。

byte getByte = buf.get()

手动读取1个buf中的字符,postion加1.

Q: 手动修改当前缓冲区的postion的方法有哪些?

A:

rewind() 将postion设置为0 mark() 可以标记1个特定的位置, 相当于打标记, 在一顿操作后,可通过reset()回到之前mark()的位置(就像你需要mark我的这几篇博文一样!)

Q:1个channel管道支持多个buffer吗?

A: 支持。 通道的write和read方法都支持传入1个buffer数组,会按照顺序做读写操作。

Buffer的种类:

Buffer的另外3个方法:

warp:

根据一个byte[]来生成一个固定的ByteBuffer时,使用ByteBuffer.wrap()非法的合适。他会直接基于byte[]数组生成一个新的buffer,值也保持一致。

slice:

得到切片后的数组。

duplicate:

调用duplicate方法返回的Buffer对象就是复制了一份原始缓冲区,复制了position、limit、capacity这些属性

注意!!!!!!

以上warp\slice\duplicte生成的缓冲区get和put所操作的数组还是与原始缓冲区一样的。 所以对复制后的缓冲区进行修改也会修改原始的缓冲区,反之亦然。

因此duplicte、slice一般是用于操作一下poistion\limit等处理,但是原内容不会去变他,否则就会引起原缓冲器的修改。

§ Selector

selector可用来在线程中关联多个通道,并进行事件监听。

Q: 在NIO中Selector的好处是什么?

A:

可以用更少的线程来管理各个通道。 减少线程上下文切换的资源开销。

Q: Selector支持注册哪种类型的通道?

A:

支持非阻塞的通道。

通道要在注册前调用 channel.configureBlocking(false) 设置为非阻塞。

例如FileChannel就没办法注册,他注定是阻塞的。而socketChannel就可以支持非阻塞。

Q: Selector注册时,支持监听哪几种事件,对应的常量是什么?(啊最不喜欢记忆这种东西了…)

A:共有4种可监听事件

Connect 成功连接到1个服务器,对应常量SelectionKey.OP_CONNECT Accept 准备好接收新进入的连接, 对应常量SelectionKey.OP_ACCEPT Read, 有数据可读,对应常量SelectionKey.OP_READ Write 接收到往里写的数据, 对应常量SelectionKey.OP_WRITE

如果希望对该通道监听多种事件,可以用"|"位或操作符把常量连接起来。

int interestingSet = Selectionkey.OP_READ | Selectionkey.OP_WRITE;

Selectionkey key = channel.register(selector,interestingSet)

SelectionKey键表示了一个特定的通道对象和一个特定的选择器对象之间的注册关系

Q: Selector维护的SelectionKey集合共有哪几种?

A:共有三种。

(1)已注册的所有键的集合 (Registered key set)

所有与选择器关联的通道所生成的键的集合称为已经注册的键的集合。并不是所有注册过的键都仍然有效。这个集合通过keys()方法返回,并且可能是空的。这个已注册的键的集合不是可以直接修改的;试图这么做的话将引发java.lang.UnsupportedOperationException。

(2)已选择的键的集合 (Selected key set)

已注册的键的集合的子集。这个集合的每个成员都是相关的通道被选择器(在前一个选择操作中)判断为已经准备好的,并且包含于键的interest集合中的操作。这个集合通过selectedKeys()方法返回(并有可能是空的)。

不要将已选择的键的集合与ready集合弄混了。这是一个键的集合,每个键都关联一个已经准备好至少一种操作的通道。每个键都有一个内嵌的ready集合,指示了所关联的通道已经准备好的操作。键可以直接从这个集合中移除,但不能添加。试图向已选择的键的集合中添加元素将抛出java.lang.UnsupportedOperationException。

(3)已取消的键的集合 (Cancelled key set)

已注册的键的集合的子集,这个集合包含了cancel()方法被调用过的键(这个键已经被无效化),但它们还没有被注销。这个集合是选择器对象的私有成员,因而无法直接访问。

注册之后, 如何使用selector对准备就绪的通道做处理:

调用select()方法获取已就绪的通道,返回的int值表示有多少通道已经就绪 从selector中获取selectedkeys 遍历selectedkeys 查看各SelectionKey中 是否有事件就绪了。 如果有事件就绪,从key中获取对应对应管道。做对应处理

类似如下,一般都会启1个线程来run这个selector监听的处理:

while(true) {

int readyNum = selector.select();

if (readyNum == 0) {

continue;

}

Set selectedKeys = selector.selectedKeys();

Iterator it = selectedKeys.iterator();

while(it.hasNext()) {

SelectionKey key = it.next();

if(key.isAcceptable()) {

// 接受连接

} else if (key.isReadable()) {

// 通道可读

} else if (key.isWritable()) {

// 通道可写

}

it.remove();

}

}

Q:select()方法其实是阻塞方法,即调用时会进入等待,直到把所有通道都轮询完毕。如果希望提前结束select(),有哪些方法?

A:有2个办法:

wakeup(), 调用后,select()方法立刻返回。

close(), 直接关闭selector。

PS: 之前说NIO是非阻塞IO,但为什么上面却说select()方法是阻塞的?

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

总结

其他的内容都可以按照路线图里面整理出来的知识点逐一去熟悉,学习,消化,不建议你去看书学习,最好是多看一些视频,把不懂地方反复看,学习了一节视频内容第二天一定要去复习,并总结成思维导图,形成树状知识网络结构,方便日后复习。

这里还有一份很不错的《Java基础核心总结笔记》,特意跟大家分享出来

目录:

部分内容截图:

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!

总结

其他的内容都可以按照路线图里面整理出来的知识点逐一去熟悉,学习,消化,不建议你去看书学习,最好是多看一些视频,把不懂地方反复看,学习了一节视频内容第二天一定要去复习,并总结成思维导图,形成树状知识网络结构,方便日后复习。

这里还有一份很不错的《Java基础核心总结笔记》,特意跟大家分享出来

目录:

[外链图片转存中…(img-1cVxtW4m-1711783722931)]

部分内容截图:

[外链图片转存中…(img-JNB7fp7B-1711783722932)]

[外链图片转存中…(img-iYuShcAW-1711783722932)] 《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!

相关阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: