Java学习总结(2.1.3) NIO非阻塞网络编程三大核心理念
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形式:
客户端主动发起和服务器的连接。
服务端获取的新连接。
write写: write()在尚未写入任何内容时就可能返回了。需要在循环中调用 write()
read读:read()方法可能直接返回而根本不读取任何数据,根据返回的int值判断读取了多少字节。
ServerSocketChannel
ServerSocketChannel可以监听新建的TCP连接通道,类似 ServerSocket
ServerSocketChannel. accept():如果该通道处于非阻塞模式,那么如果没有挂起的连接,该方法将立即返回null。必须检查返回的 Socket Channel是否为null。
Selectors选择器
Selectors是一个 Java NIO:组件,可以检查一个或多个NIO通道,并确定哪些通道已准备好进行读取或写入。实现单个线程可以管理多个通道,从而管理多个网络连接。
一个线程使用 Selector监听多个 channele的不同事件:
四个事件分别对应SelectionKey四个常量。
Connect连接(Selectionkey.OP_CONNECT)
Accept准备就绪(OP_ACCEPT)
Read读取(OP_READ)
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等。
每日一句
博客分组
标签云
- 最近综合
- 情绪巨婴是什么 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