文章目录
1. 概述
⑴阻塞非阻塞,同步异步的区别
- 阻塞 在调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会被唤醒执行后续的操作。
- 非阻塞 在结果没有返回之前,该调用不会阻塞住当前线程。
- 同步 同步就是发起一个请求,直到请求返回结果之后,才进行下一步操作
- 异步 当一个异步操作发出后,调用者在没有得到结果之前,可以继续执行后续操作
⑵什么是NIO
是一种同步非阻塞的I/O模型,也是I/O多路复用的基础。
⑶NIO组成
- Buffer
- Channel
- Selector
⑷NIO与IO的区别
- IO面向流,NIO面向缓冲
- 面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方
- 面向缓冲数据读取到一个它稍后处理的缓冲区
- IO是阻塞的,NIO可以非阻塞
- 阻塞IO: 资源不可用时,IO请求一直阻塞,直到反馈结果(有数据或超时)
- 非阻塞IO:资源不可用时,IO请求离开返回,返回数据标识资源不可用
- Java IO的各种流是阻塞的,NIO有阻塞的也有非阻塞的
- NIO有个选择器(Selectors),使用一个单独的线程来监视多个输入通道
2 Buffer
⑴概述
Java NIO中的Buffer用于和NIO通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中的
⑵Buffer的容量,位置,上限(Buffer Capacity, Position and Limit)
buffer缓冲区实质上就是一块内存
- 容量 也就是最多只能写入容量的数据。一旦buffer写满了就需要清空已读数据以便下次继续写入新的数据
- 位置 默认位置是0,每次读取或写入,position向后移动
- 上限 在写模式下就等于容量,在读模式下是你从写切换时的position值(也就是写多少读多少)
⑶Buffer的类型
ByteBuffer
MappedByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
就是可以通过char,short,int,long,float或double类型来操作缓冲区中的字节
3 CHANNEL
⑴概述
通道总是基于缓冲区Buffer来读写
⑵Channel常用类
- FileChannel 用于文件的数据读写(阻塞模式)
- DatagramChannel 用于UDP的数据读写(阻塞/非阻塞)
- SocketChannel 用于TCP的数据读写(阻塞/非阻塞)
- ServerSocketChannel 允许我们监听TCP链接请求,每个请求会创建会一个SocketChannel(阻塞/非阻塞)
- AsynchronousFileChannel 异步读写文件(非阻塞)
4.Selector
Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel。
注册到server上的channel必须设置成异步模式,否则异步io无法工作,这就意味着我们不可以把一个Filechannel注册到selector,因为filechannel没有异步模式,但是socketchannel有异步模式。
注册的时候我们可以选择selector对channel中的那些事务感兴趣,包含:
- Wirte:SelectionKey.OP_WRITE
- Read:SelectionKey.OP_READ
- Accept:SelectionKey.OP_ACCEPT
- Connect:SelectionKey.OP_CONNECT
5.Reactor
⑴概述
java的NIO是属于同步非阻塞IO,关于IO多路复用,java没有相应的IO模型,但有相应的编程模式,Reactor 就是基于NIO中实现多路复用的一种模式,Netty就使用了Reactor模型
⑵核心理念
- 依赖于非阻塞IO。
- 使用多路复用器监管海量IO的就绪事件。
- 使用Boss线程和Work线程池分离IO事件的监测与IO事件的处理。
⑶角色
- Acceptor。用户处理客户端连接请求。
- Reactor。用于分派IO就绪事件的处理任务,相当于有分发功能的Selector。Reactor角色映射到Java代码中,即为使用多路复用器的Boss线程。
- Handler。用于处理具体的IO就绪事件。(比如读取并处理数据等)。Handler角色映射到Java代码中,即为Worker线程池中的每个线程。
⑷线程模型
⑴单线程模型
Reactor 线程是个多面手,负责多路分离套接字,Accept 新连接,并分派请求到处理器链中。该模型适用于处理器链中业务处理组件能快速完成的场景。不过这种单线程模型不能充分利用多核资源,所以实际使用的不多。
⑵多线程模型(单 Reactor)
将非I/O操作从Reactor线程中移出转交给工作者线程池来执行,这样能够提高Reactor线程的I/O响应,不至于因为一些耗时的业务逻辑而延迟对后面I/O请求的处理。
⑶多线程模型(多 Reactor)
它是将 Reactor 分成两部分,mainReactor 负责监听并 Accept新连接,然后将建立的 socket 通过多路复用器(Acceptor)分派给subReactor。subReactor 负责多路分离已连接的 socket,读写网络数据;业务处理功能,其交给 worker 线程池完成。通常,subReactor 个数上可与 CPU 个数等同。