讨论集合

乒乓狂魔原文地址

必读文章

  • 并发编程网:Java NIO系列教程

  • infoq:Netty系列之Netty线程模型

  • infoq:Java NIO通信框架在电信领域的实践

  • 经典tcp粘包分析

  • Mina、Netty、Twisted一起学

  • 理解Java NIO

  • Netty系列之Netty编解码框架分析


阻塞与非阻塞区别/同步与异步区别

同步方式:执行时,一定要等待函数执行完返回结果才行。

异步方式:执行时,调用时不立即得到返回结果,而是当实际执行完成之后,通过状态、通知、回调等通知调用者。

阻塞模式:在没有得到返回结果之前,当前线程挂起。

非阻塞模式:指在不能立刻得到结果之前,该函数不会挂起当前线程,而会立刻返回。

阻塞和非阻塞不一定就和线程挂钩,LinkedBlockingQueue 就是一种阻塞式的队列。

如java中的固定长度的集合,你往集合中放置一个元素,如果此时集合已经满了,就会出现两种情况,一种就是你等待直到该集合不满,一种选择就是直接返回不操作

疑问解答:有人也许会把阻塞调用和同 步调用等同起来,实际上它们是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。例如,我们在CSocket中 调用Receive函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消息。如果主窗口和调 用函数在同一个线程中,除非你在特殊的界面操作函数中调用,其实主界面还是应该可以刷新。socket接收数据的另外一个函数recv则是一个阻塞调用的 例子。当socket工作在阻塞模式的时候, 如果没有数据的情况下调用该函数,则当前线程就会被挂起,直到有数据为止。

FileChannel为什么为非阻塞

阻塞与非阻塞IO

Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。

Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)

nio服务建立步骤

讨论集合_第1张图片

Selector:

其实是由SelectorProvider来提供实现的,而SelectorProvider本身则是通过系统属性或者使用SPI机制来获取的


ZooKeeper中目前是只有一个线程来处理NIO通信和编解码的。

就是Reactor单线程模型

当NIO线程负载过重之后,处理速度将变慢,这会导致大量客户端连接超时,超时之后往往会进行重发,这更加重了NIO线程的负载,最终会导致大量消息积压和处理超时,成为系统的性能瓶颈。模型如下图:讨论集合_第2张图片

当NIO线程负载过重之后,处理速度将变慢,这会导致大量客户端连接超时,超时之后往往会进行重发,这更加重了NIO线程的负载,最终会导致大量消息积压和处理超时,成为系统的性能瓶颈

升级版--添加线程池:讨论集合_第3张图片

两种实现方式:

一种实现方式

种就是大家全部注册到同一个Selector上,只不过在执行IO操作的时候由线程池去执行

另一种方式

每个线程都含有一个Selector,每个Channel就固定在了某个线程上的Selector上了,每个线程都在轮训的Selector来执行该Selector上注册的Channel事件。

其实后一种方式减少了并发操作,应该是避免了对同一个Channel的并发操作。

而Netty中就是第二种的形式:

NioEventLoopGroup是 NioEventLoop的集合形式
每一个NioEventLoop:包含一个线程和一个Selector selector复用器
因此一个NioEventLoop就可以处理很多链路(channel),每个链路(channel)的读写操作全部交给这一个线程来处理,避免了并发操作同一个链路(channel)的可能性
每当有一个新的客户端接入,则从NioEventLoop线程组中顺序获取一个可用的NioEventLoop,当到达数组上限之后,重新返回到0,通 过这种方式,可以基本保证各个NioEventLoop的负载均衡。一个客户端连接只注册到一个NioEventLoop上,这样就避免了多个IO线程去 并发操作它

每个NioEventLoop都在不断的执行他们的Selector中的事件,当你把一个连接注册交给某个NioEventLoop时,其实就是将该Channel注册到该NioEventLoop上的Selector上,也就是说该Channel的读写事件是由该Selector来负责了

再来看看编解码问题和序列化问题

我们知道TCP协议中都是面向字节进行传输的
这就需要在数据发送时需要将数据转换成字节,在数据接收时需要将字节转换成对应的数据

tcp粘包问题

TCP是基于字节流的协议,它只能保证一方发送和另一方接收到的数据的字节顺序一致,但是,并不能保证一方每发送一条消息,另一方就能完整的接收到一条信息

讨论集合_第4张图片

这种现象就叫做tcp粘包问题
UDP则没有这种问题

解决办法:

- 使用固定长度的消息
- 使用分隔符
- 使用固定长度的Header加Body的形式(如http协议,dubbo协议

我们来看下dubbo协议的实现:

dubbo协议中Header是固定长度,每一个位置都包含着特殊意义,Header中的最后指定了Body的长度大小。

讨论集合_第5张图片

而body中的内容则是需要序列化框架来进行处理的,Header部分则可以看成是需要编解码来处理的


讨论集合_第6张图片

序列化和反序列化框架的职责就是对象和字节数组之间的转化,它不考虑之外的其他事情;而编解码器则是需要来处理半包问题的,半包就是只接收到了一部分数据,还不能被使用,需要等到接收全部数据后才会被交给序列化框架来处理

讨论遗留问题:

1.阻塞与非阻塞和同步与异步的区别?
2.nio的fileChannel非阻塞是怎么实现的机制是什么?
3.netty实现框架运用什么原理?selector和channel是怎么使用线程池的?
4.UDP为什么不会出现粘包?
5.NIO中的非阻塞体现在哪?

你可能感兴趣的:(netty,nio,群内讨论)