事件驱动模型的角度来看 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
private Set
private final Set
(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 做准备