NIO之三大组件

java1.4引入了NIO.标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作.

NIO中的读操作是从channel到buffer,写操作是从buffer到channel

标准IO中流总是单向的,channel则是双向的,数组总是从channel读到buffer,然后再从buffer取出。或者先写入buffer,再从buffer进入到channe中传输到目标方

Buffer

// Invariants: mark <= position <= limit <= capacity
    private int mark = -1;
    private int position = 0;
    private int limit;
    // 固定大小,满了需要清空(读/清除)
    private int capacity;

position取决于读或者写,每写入一个数据,position向前移动一位。position最大可为capacity – 1.从写模式切换到读模式时,position会变为0,同时,每读一位,position向后移动一位。

写模式下,limit等于Buffer的capacity。 当切换Buffer到读模式时,此时的 limit 等于 Buffer 中实际的数据大小,因为 Buffer 不一定被写满了。

buffer的初始化
2中方法:

// 1
ByteBuffer buffer=ByteBuffer.allocate(1024);
// 2
ByteBuffer writeBuffer=ByteBuffer.wrap(("我已经收到你的请求,你的请求内容是"+re).getBytes());

填充buffer

有可以自己控制填充数据的put方法比如

// 填充一个 byte 值
public abstract ByteBuffer put(byte b);

// 将一个数组中的值填充进去
public final ByteBuffer put(byte[] src) {...}

最常用的还有就是很常用的从channel来的数据,会先进入buffer才能被读取到

int num = channel.read(buf);  // num即从channel读入到buffer的数据大小

获取buffer中的值
获取buffer值的过程一定是在从channel向buffer中写入之后,所以需要先从写模式切换到读模式,采用flip()

public final Buffer flip() {
    limit = position; // 将 limit 设置为实际写入的数据数量
    position = 0; // 重置 position 为 0
    mark = -1; // mark 之后再说
    return this;
}

对应填充buffer的put,这里还有很多get函数获取

// 将 Buffer 中的数据写入到数组中
public ByteBuffer get(byte[] dst)

// 根据当前position 来获取数据
public abstract byte get();

// 获取buffer中的字节数组
buffer.array()
将buffer中的值写入到channel
int num = channel.write(buf);

clear&&compact

public final Buffer clear() {
    position = 0;
    limit = capacity;
    mark = -1;
    return this;
}

重置buffer,相当于创建buffer新实例,可以看到数据并没有被清除,但是当新的数据到来时,原来数据会被覆盖,也就相当于清除

compact则是会保留原来数据调用这个方法以后,会先处理还没有读取的数据,也就是 position 到 limit 之间的数据(还没有读过的数据),先将这些数据移到左边,然后在这个基础上再开始写入。很明显,此时 limit 还是等于 capacity,position 指向原来数据的右边。

Buffer的工作无非就是
put() 一下数据、flip() 切换到读模式、然后用 get() 获取数据、clear() 一下清空数据、重新回到 put() 写入数据。

Selector

非阻塞的实现就是基于selector,所谓的多路复用,即是一个线程管理多个channel

Selector 建立在非阻塞模式之上,所以注册到 Selector 的 Channel 必须要支持非阻塞模式

select()
调用此方法,会将上次 select 之后的准备好的 channel 对应的 SelectionKey 复制到 selected set 中。如果没有任何通道准备好,这个方法会阻塞,直到至少有一个通道准备好。

selectNow()
功能和 select 一样,区别在于如果没有准备好的通道,那么此方法会立即返回 0。

select(long timeout)
看了前面两个,这个应该很好理解了,如果没有通道准备好,此方法会等待一会

wakeup()
这个方法是用来唤醒等待在 select() 和 select(timeout) 上的线程的。如果 wakeup() 先被调用,此时没有线程在 select 上阻塞,那么之后的一个 select() 或 select(timeout) 会立即返回,而不会阻塞,当然,它只会作用一次。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值