一、Buffer梳理
1.1 字段解释
表中几个字段的数学关系是:0 <= mark
<= positon
<= limit
<= capacity
字段名 |
说明 |
备注 |
capacity |
buffer容量 |
比如在ByteBuffer.allocate(1024) 表示将容量设置为1024 |
position |
当前指针偏移量 |
比如在新创建的byteBuffer中put() 一个byte,此时position 由0变为1 |
limit |
限制指针的大小 |
比如ByteBuffer.allocate(1024) 此时limit 为1024,所以position 最大为1024。 |
mark |
临时标记,默认是未定义的 |
假设IntBuffer.allocate(1024) ,现在position 位置为10,现在只想发送512到1024之间的缓冲数据,此时我们可以buffer.mark(buffer.position()) 既将position记入mark位置,然后buffer.postion(512) ,此时发送的数据就是512到1024之间的数据。发送完成后,调用buffer.reset() 将mark临时标记赋值给position 使得position=mark 。注意如果未设定mark ,而调用了buffer.reset() 方法则会抛出InvalidMarkException |
1.2 方法汇总
方法 |
说明 |
备注 |
capacity() |
获取容量大小 |
|
position() |
获取当前值的偏移量 |
|
position(int newPosition) |
设置偏移量指针未知 |
newPosition 需要小于capacity |
limit() |
获取当前limit 大小 |
|
limit(int newLimit) |
设置当前limit 大小 |
limit 应该小于等于capacity 并大于0 |
mark() |
记录当前的偏移量位置 |
即 mark=position |
reset() |
重置为先前偏移量的位置 |
本方法一般要和mark() 方法配合使用,当没有初始化mark() 值会抛出InvalidMarkException 异常 |
clear() |
清除缓冲区 |
将position=0,limit=capacity,mark=-1 |
flip() |
读写翻转 |
将limit=position,position=0,mark=-1 。需要注意假设一个position=1,capacity=1024 的读状态的buffer翻转此时limit=1而不是1024 |
rewind() |
回退缓冲区 |
他只是将position=0 和mark=-1 |
remaining() |
返回当前位置和limit之前的元素数 |
|
hasRemaining() |
判断当前位置和limit之前是否还存在元素 |
二、Channel梳理
1.1 基本介绍
channel可以同时进行读写而流只能读或者写
channel可以从buffer中读数据,也可以向buffer中写数据
常用的 Channel
类有:FileChannel
、DatagramChannel
、ServerSocketChannel
、SocketChannel
、ServerSocketChannel
、SocketChannel
三、Selector梳理
3.1 基本介绍
- Java 的 NIO,用非阻塞的 IO 方式。可以用一个线程,处理多个的客户端连接,就会使用到Selector(选择器)
- Selector 能够检测多个注册的通道上是否有事件发生(注意:多个Channel以事件的方式可以注册到同一个Selector),如果有事件发生,便获取事件然后针对每个事件进行相应的处理。这样就可以只用一个单线程去管理多个通道,也就是管理多个连接和请求。
- 只有在 连接/通道 真正有读写事件发生时,才会进行读写,就大大地减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程4) 避免了多线程之间的上下文切换导致的开销
3.2 方法汇总
方法名 |
说明 |
备注 |
open() |
创建一个selector |
|
isOpen() |
判断当前selector是否开启 |
|
keys() |
返回当前selector注册的所有channel的selectionKey |
|
selectedKeys() |
返回当前selector中等待io操作的channel的selectionKey |
|
selectNow() |
通过非阻塞的方式获取当前等待io的channel的键数量 |
|
select() |
通过阻塞的方式获取当前等待io的channel的键数量 |
|
select(long timeout) |
同上,只不过多了一个等待超时时间 |
|
wakeup() |
唤醒阻塞的select() |
调用wakeup()没有select操作,下次调用select相关操作立即返回,不执行poll(),包括selectNow()。多次调用与一次效果一样 |