Java学习总结(2.1.3) NIO非阻塞网络编程三大核心理念

精贴 置顶
1618 0
作者:      发布时间: 2020-04-17 15:54:33

JAVA NIO

始于Java1.4,提供了新的 JAVA IO操作非阻塞API。

用意是替代 Java IO和 Java Networking相关的APl。


NIO中有三个核心组件:

Buffer缓冲区

Channel通道

Selector选择器


Buffer缓冲区

缓冲区本质上是一个可以写入数据的内存块(类似数组),然后可以再次读取。此内存块包含在 NIO Buffer对象中,该对象提供了一组方法,可以更轻松地使用内存块。相比较直接对数组的操作, Buffer API更加容易操作和管理。


使用 Buffer进行数据写入与读取,需要进行如下四个步骤:

1.将数据写入缓冲区

2.调用 buffer.fip,转换为读取模式

3.缓冲区读取数据

4.调用 buffer clear()或 buffer. compact()清除缓冲区


Buffer工作原理

Buffer三个重要属性

capacity容量:作为一个内存块, Buffer!具有一定的固定大小,也称为“容量”。

position位置:写入模式时代表写数据的位置。读取模式时代表读取数据的位置。

limit限制:写入模式,限制等于 buffer的容量。读取模式下,imit等于写入的数据量。


ByteBuffer内存类型

ByteBuffer为性能关键型代码提供了直接内存( directt雄外)和非直接内存(heap堆)两种实现。

堆外内存获取的方式: Bytebuffer directBytebuffer= Bytebuffer. allocatedirect( nobytes);


好处

1、进行网络IO或者文件IO时比heapbuffer少ー次拷贝。(file/socket---OS memory---jvm heap)

    GC会移动对象内存,在写file或socket的过程中,JVM的实现中,会先把数据复制到堆外,再进行写入。

2、GC范围之外,降低GC压力,但实现了自动管理。 

Directbytebuffer中有一个 Cleaner对象( Phantom Reference), Cleaner被GC前会执行 clean方法,触发 DirectBytebuffert中定义的Deallocator


建议

1、性能确实可观的时候オ去使用;分配给大型、长寿命;(网络传输、文件读写场景)

2、通过虚拟机参数MaxDirectmemorysize限制大小,防止耗尽整个机器的内存


Channel通道

Channel的API涵盖了UDP/TCP网络和文件IO:

FileChannel

DatagramChannel

SocketChannel

ServerSocketChannel


和标准IO Stream操作的区别:

在一个通道内进行读取和写入

stream通常是单向的(input或 output)

可以非阻塞读取和写入通道

通道始终读取或写入缓冲区


SocketChannel

SocketChannel用于建立TCP网络连接,类似java.net.Socket。

有两种创建 socketChanne形式:

  1. 客户端主动发起和服务器的连接。

  2. 服务端获取的新连接。


write写: write()在尚未写入任何内容时就可能返回了。需要在循环中调用 write()

read读:read()方法可能直接返回而根本不读取任何数据,根据返回的int值判断读取了多少字节。



ServerSocketChannel

ServerSocketChannel可以监听新建的TCP连接通道,类似 ServerSocket


ServerSocketChannel. accept():如果该通道处于非阻塞模式,那么如果没有挂起的连接,该方法将立即返回null。必须检查返回的 Socket Channel是否为null。



Selectors选择器

Selectors是一个 Java NIO:组件,可以检查一个或多个NIO通道,并确定哪些通道已准备好进行读取或写入。实现单个线程可以管理多个通道,从而管理多个网络连接。


一个线程使用 Selector监听多个 channele的不同事件:

四个事件分别对应SelectionKey四个常量。

  1. Connect连接(Selectionkey.OP_CONNECT)

  2. Accept准备就绪(OP_ACCEPT)

  3. Read读取(OP_READ)

  4. Write写入(OP_WRITE)


实现一个线程处理多个通道的核心概念理解:事件驱动机制。

非阻塞的网络通道下,开发者通过Selector注册对于通道感兴趣的事件类型,线程通过监听事件来触发相应的代码执行。(拓展:更底层是操作系统的多路复用机制)





NIO对比BIO

BIO线程模型

阻塞IO,线程等待时间长

一个线程负责一个连接处理

线程多且利用率低


NIO线程模型

非阻塞IO,线程利用率更高

一个线程处理多个连接事件

性能更强大


如果你的程序需要支撑大量的连接,使用NIO是最好的方式。

Tomcat8中,已经完全去除BIO相关的网络处理代码,默认采用NIO进行网络处理。



NIO与多线程结合的改进方案

Doug Lea的著名文章《Scalable lo in Java》

http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf



Reactor线程接收请求->分发给线程池处理请求

mainReactor接收->分发给 subreactor读写->具体业务逻辑分发给单独的线程池处理



小结

NIO为开发者提供了功能丰富及强大的IO处理API,但是在应用于网络应用开发的过程中,直接使用JDK提供的APl,比较繁琐。而且要想将性能进行提升,光有NIO还不够,还需要将多线程技术与之结合起来。

因为网络编程本身的复杂性,以及 JDK API开发的使用难度较高,所以在开源社区中,涌出来很多对 JDK NIO进行封装、增强后的网络编程框架,例如:Netty、Mina等。








标签:

每日一句

如果你能每天呐喊二十一遍「我用不着为这一点小事而烦恼」,你会发现,你心里有一种不可思议的力量。

标签云

vue
最近综合
情绪巨婴是什么 12.18
普通蛋糕做法 05.31
玉米烤肠芝士面包做法 05.31
Mysql安装教程 - 绿色版 06.18
我们学习知识为什么总是忘记呢?【学习金字塔】 05.12
Typora开发版⽆法使⽤解决⽅法 05.04
为什么无知者越自信? -- 达克效应 05.10
马斯洛需求层次理论 04.29
随机综合
中间件1.2.2-ActiveMQ支持的消息协议讲解 04.23
Typora开发版⽆法使⽤解决⽅法 05.04
鸿蒙OS代码正式开源 09.11
开发者能力金字塔 04.29
Java学习总结(1.1.5) 线程通信 03.18
[vue]npm启动导入/运行vue的项目 08.05
php 用万网空间,提交数据中出现反斜杠问题 04.13
Java学习总结(1.1.2) 线程状态 03.17