【Java NIO 简例】非阻塞服务端

原文:《Java NIO: Non-blocking Server》GitHub 上的实例代码https://github.com/jjenkov/java-nio-server非阻塞IO管道非阻塞IO管道是一系列组件的链接。简化结构如下(读写都适用):Component 利用 Selector 来监测是否有 Channel 就绪可供读取数据;Comp...
摘要由CSDN通过智能技术生成

 

原文:《Java NIO: Non-blocking Server

GitHub 上的实例代码

https://github.com/jjenkov/java-nio-server

 

非阻塞IO管道

非阻塞IO管道是一系列组件的链接。简化结构如下(读写都适用):

 

Component 利用 Selector 来监测是否有 Channel 就绪可供读取数据;

Component 读取这些输入数据,并基于此生成输出数据;

最后将这些输出数据写到另一个 Channel 中。

 

非阻塞IO管道并不一定同时可读可写。它可以 只读 或 只写。

 

在实际项目中,一个管道可能会有对个对应的 Component 来处理输入的数据;管道的长度也会因业务需要而不同。

 

从 Channel 到 Selector,从 Selector 到 Component 的箭头其实是 Component 在处理 Selector 与 Channel,而不是 Channel 主动将数据推送到 Selector。

 

IO管道:非阻塞 vs 阻塞

非阻塞 与 阻塞IO 的最大区别在于对 channel/stream 的读写方式的不同。

在典型的读取stream数据场景中,可认为有一个 Messager Reader 将stream中的数据分块读出。

在阻塞式IO中,可以从一个 InputStream 读取数据;如果 InputStream 中的数据尚未就绪,这个操作将一直阻塞,直到有数据可读。这导致 Messager Reader 是阻塞式的。

阻塞式的 stream 简化了 Message Reader 的实现。因为无需处理stream中无数据就绪,或只有部分数据就绪的情况。

阻塞式写入stream的操作也类似,无需处理只有部分数据写入stream的情况。

 

阻塞式IO管道的缺点

虽然阻塞式 Message Reader 更容易实现,但它需要为每个stream创建一个线程来处理数据。

因为stream在数据就绪前会一直阻塞。这导致单个线程无法在 “尝试读取某个stream,但stream数据未就绪” 的情况下转而去读取另一个stream。因为一个线程一旦尝试去stream读数据,它将被阻塞,直到stream中数据就绪。

 

对于一批来自客户端的并发连接,服务端必须为吗,每个连接创建一个线程进行处理。如果在任一时刻,并发连接数只有几百,也不会有什么问题。但如果是上百万的并发连接,这种阻塞式的设计就无法良好运行。每个线程的线程栈会消耗320KB(32位JVM)或1024KB(64位JVM)的内存。1百万个线程消耗将近1TB的内存!这还没算上服务器用于处理数据的内存。

 

为了降低线程数量,许多服务端都使用了 线程池 的设计。

来自客户端的连接被维护在一个队列中。一旦线程池中有空闲线程,就从队列中取一个连接,由该线程处理。简化结构如下:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值