您的位置:首页 > 编程语言 > Java开发

事件驱动模型的角度来看看 JAVA NIO

2016-02-11 00:51 597 查看

事件驱动模型的角度来看看 JAVA NIO

事件驱动模型的角度来看看 java nio,先作知识的简单铺垫,

1,阻塞非阻塞

阻塞式I/O模型:

(1)等待数据准备好;

(2)从内核向进程复制数据。

2,非阻塞式I/O: 当所请求的I/O操作非得把本进程投入睡眠才能完成时,不要把进程投入睡眠,而是返回一个错误。进而不断的通过轮询方式来获取正确的结果

3,I/O多路复用:虽然I/O多路复用的函数也是阻塞的,但是其与以上两种还是有不同的,I/O多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用。

阻塞,非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否需要等待;

同步,异步:访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞;异步只需要I/O操作完成的通知,并不主动读写数据,由操作系统内核完成数据的读写。

这里只是简单的概述而已

4.nio 主要模块介绍



selector 主要负责监听io事件,channel这里可以简单理解对于数据的操作,我觉得把它理解为socket 吧好理解一点,比如发送数据和读取数据,buffer 则是将数据进行读入和读取,对于buffer的理解可以参照java io 读取的文件的buffer

5,java nio 开发流程架构



6,代码的实现:

(1)Reactor 构造函数

public Reactor(int port) throws IOException {
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(port));
serverSocketChannel.configureBlocking(false);
SelectionKey selectionKey =  serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
selectionKey.attach(new Acceptor());

}


Reactor是一种事件驱动模型;使用Selector 有如下方法

a. public static Selector open();

该方法获取一种io 多路复用的机制,比如linux 2.6+平台java提供的是epoll 机制,mac os x 提供的是kqueue机制,这里就不对io 复用探讨

b. 获取server channel 对象进行绑定监听端口

c. 设置服务方式为非阻塞方式

d. 将channel 注册到selector 上,让selector 去管理我们关心的io

e. SelectionKey 理解为selector 和 channel 之间的抽象

(2)实现Runable接口的run 方法

public void run() {
try {
while (!Thread.interrupted()) {
selector.select();
Set selected = selector.selectedKeys();
Iterator it = selected.iterator();
//循环的遍历,可以操作的事件
while (it.hasNext())
//将读取到的事件进行分发
dispatch((SelectionKey)(it.next()));
selected.clear();
}
} catch (IOException e){

}
}


Selector是java nio 中的多路复用器,配合SelectionKey使用,SelectionKey代表着一个Channel和Selector的关系的抽象,Channel向Selector注册的时候产生,由Selector维护。Selector维护着三个SelectionKey的集合:

private Set publicKeys; 当有SelectionKey关联的Channel有Channel向Selector注册的IO事件就绪的时候并且有select操作,对应的SelectionKey会被放到publicSelectedKeys中。因为这个集合中的SelectionKey可以通过直接调用Set的remove将SelectionKey移除。

private Set publicSelectedKeys 当有SelectionKey关联的Channel有Channel向Selector注册的IO事件就绪的时候并且有select操作,对应的SelectionKey会被放到publicSelectedKeys中。因为这个集合中的SelectionKey可以通过直接调用Set的remove将SelectionKey移除。

private final Set cancelledKeys 当有已经向Selector注册的Channel发生degistered的时候,SelectionKey将被放到这个集合,并且在下一次select的时候被从所有的集合中移出。

(3)Acceptor 类:

class Acceptor implements Runnable {

public void run() {
try {
SocketChannel c = serverSocketChannel.accept();
if (c != null)
new Thread(new Handler(c,selector)).start();
}
catch(IOException ex) {
}
}
}


这里就是获取到相应的channel 对象,然后交给处理线程 handler去处理

(4)dispatch 方法:

private void dispatch(SelectionKey k) {
Runnable r = (Runnable)(k.attachment());
if (r != null)
r.run();
}


这里 SelectionKey .attachment 使用的是AtomicReferenceFieldUpdater 这个类的方法 原子更新

(5)Handler 类

public Handler(SocketChannel socketChannel, Selector selector) throws IOException {
this.socketChannel = socketChannel;
socketChannel.configureBlocking(false);
selectionKey = socketChannel.register(selector, 0);
selectionKey.attach(this);
selectionKey.interestOps(SelectionKey.OP_READ);
selector.wakeup();

}

public void run() {
if (state == READING) read();
else if (state == SENDING) send();
}


逻辑,就是让selector 继续侦听我们注册的事件,然后对于数据进行read write 操作而已

代码地址

至此整个reactor 的基本架构已经结束,此次纪录为后面的netty 做准备
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java nio 数据