java中的NIO和IO到底是什么区别?20个问题告诉你答案

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());

结果如下

img

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数组,会按照顺序做读写操作。

img

Buffer的种类:

img

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可用来在线程中关联多个通道,并进行事件监听。

img

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对准备就绪的通道做处理:

  1. 调用select()方法获取已就绪的通道,返回的int值表示有多少通道已经就绪

  2. 从selector中获取selectedkeys

  3. 遍历selectedkeys

  4. 查看各SelectionKey中 是否有事件就绪了。

  5. 如果有事件就绪,从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工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

img

img

img

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

如果你觉得这些内容对你有帮助,可以扫码领取!

img

Kafka实战笔记

关于这份笔记,为了不影响大家的阅读体验,我只能在文章中展示部分的章节内容和核心截图

image.png

  • Kafka入门
  • 为什么选择Kafka
  • Karka的安装、管理和配置

image.png

  • Kafka的集群
  • 第一个Kafka程序
  • image.png

afka的生产者

image.png

  • Kafka的消费者
  • 深入理解Kafka
  • 可靠的数据传递

image.png

image.png

  • Spring和Kalka的整合
  • Sprinboot和Kafka的整合
  • Kafka实战之削峰填谷
  • 数据管道和流式处理(了解即可)

image.png

  • Kafka实战之削峰填谷

image.png

iN-1711377945261)]

afka的生产者

[外链图片转存中…(img-c5YeCuCF-1711377945261)]

  • Kafka的消费者
  • 深入理解Kafka
  • 可靠的数据传递

[外链图片转存中…(img-ISxAeBCd-1711377945261)]

[外链图片转存中…(img-AL5iL4vz-1711377945261)]

  • Spring和Kalka的整合
  • Sprinboot和Kafka的整合
  • Kafka实战之削峰填谷
  • 数据管道和流式处理(了解即可)

[外链图片转存中…(img-arhaFhRA-1711377945261)]

  • Kafka实战之削峰填谷

[外链图片转存中…(img-CRTGgdIV-1711377945262)]

需要更多Java资料的小伙伴可以帮忙点赞+关注,点击传送门,即可免费领取!

  • 15
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值