标签:
1. Reactor的由来
Reactor是一种广泛应用在服务器端开发的设计模式。Reactor中文大多译为“反应堆”,我当初接触这个概念的时候,就感觉很厉害,是不是它的原理就跟“核反应”差不多?后来才知道其实没有什么关系,从Reactor的兄弟“Proactor”(多译为前摄器)就能看得出来,这两个词的中文翻译其实都不是太好,不够形象。实际上,Reactor模式又有别名“Dispatcher”或者“Notifier”,我觉得这两个都更加能表明它的本质。
那么,Reactor模式究竟是个什么东西呢?这要从事件驱动的开发方式说起。我们知道,对于应用服务器,一个主要规律就是,CPU的处理速度是要远远快于IO速度的,如果CPU为了IO操作(例如从Socket读取一段数据)而阻塞显然是不划算的。好一点的方法是分为多进程或者线程去进行处理,但是这样会带来一些进程切换的开销,试想一个进程一个数据读500ms,期间进程切换到它3次,但是CPU却什么都不能干,就这么切换走了,是不是也不划算?
这时先驱们找到了事件驱动,或者叫回调的方式,来完成这件事情。这种方式就是,应用业务向一个中间人注册一个回调(event handler),当IO就绪后,这个中间人产生一个事件,并通知handler进行处理。这种回调的方式,也体现了“好莱坞原则”——“Don‘t call us,we‘ll call you”。
好了,我们现在来看Reactor模式。在前面事件驱动的例子里有个问题:我们如何知道IO就绪就个事件,谁来充当这个中间人?Reactor模式的答案是:由一个不断等待和循环的单独进程(线程)来做这件事,它接受所有handler的注册,并负责先操作系统查询IO是否就绪,在就绪后就调用指定handler进行处理,这个角色的名字就叫做Reactor。
2. Reactor与NIO
Java中的NIO可以很好的和Reactor模式结合。关于NIO中的Reactor模式,我想没有什么资料能比Doug Lea大神(不知道Doug Lea?看看JDK集合包和并发包的作者吧)在《Scalable IO in Java》解释的更简洁和全面了。NIO中Reactor的核心是Selector,我写了一个简单的Reactor示例,注意这里有一个核心的Reactor的循环(这种循环结构又叫做EventLoop):
package us.codecraft.netty.reactor;
import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
public class Handler implements Runnable {
final SocketChannel socket = null;
final SelectionKey sk;
Handler(Selector sel) throws IOException{
socket.configureBlocking(false);
sk = socket.register(sel,0);
sk.attach(this);
sk.interestOps(SelectionKey.OP_READ);
sel.wakeup();
}
@Override
public void run(){
//TODO:处理逻辑
}
}
package us.codecraft.netty.reactor;
import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.Set;
public class Reactor implements Runnable{
Selector selector;
public Reactor() throws IOException {
selector = Selector.open();
}
public void run(){
try{
while(!Thread.interrupted()){
//循环,等待事件
selector.select();
Set selected = selector.selectedKeys();
Interator it = selected.iterator();
while(it.hasNext())
//调用handler,处理事件
dispatch((SelectionKey)(it.next()));
selected.clear();
}
}catch(IOException ex){
}
}
void dispatch(SelectionKey k) {
Runnable r = (Runnable) (k.attachment());
if(r != null) r.run();
}
}
package us.codecraft.netty.reactor;
import java.io.IOException;
public class Main{
public static void main(String[] args) throws IOException {
Reactor reactor = new Reactor();
new Handler(reactor.selector);
reactor.run();
}
}
标签:
原文地址:http://my.oschina.net/fhd/blog/378815