Reactor设计模式

NIO用到的Reactor设计模式,下面的说明比较清楚,留作记录。

 

Reactor设计模式和观察者模式非常相似,但是它比观察者模式复杂,Reactor设计模式使用一个Selector对象相当于观察模者式里面观察者,每个
SocketServerChannal 实例和SocketChannal实例都相当于被观察者,当然它们需要在Selector对象里面注册,它们注册之后每个Channal实例都会分配一个 SelectionKey对象,SelectionKey对象可以attach(附带)一个对象,当Selector里面注册channal有事件发生 时,Selector就会产生一个遍历,这时候可以在遍历时候用attachment()方法把每个SelectionKey里面attach对象o 提出来,你可以在这个时候运行在o对象所属类O里面所定义方法,在这个方法里面可以使用socket.read()方法进行读取网络数据,将数据读出 后,可以将这些数据处理线程做成一个线程池,这样,数据读出后,立即扔到线程池中,这样加速处理速度。
注意在每次遍历提出SelectionKey,对注册channal读或写进行处理完毕之后,需要对channal进行重新注册,重新attach()对象。


使用nio提供Reactor设计模式,我们可以设计一个高性能nio服务器:
1、启动一个实现Runnable接口Reactor,在Reactor构造方法里面使用Selector.open()方法实例化一个Selector。
2、打开一个ServerSocketChannal,代码:
ServerSocketChannel serverSocket = ServerSocketChannel.open();
InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(),port);
serverSocket.socket().bind(address);
serverSocket.configureBlocking(false);
3、将ServerSocketChannal在selector里进行注册,代码:
SelectionKey sk =serverSocket.register(selector,SelectionKey.OP_ACCEPT);
4、给sk附带上一个事件处理对象,代码:
sk.attach(new Acceptor());
5、在Reactor类run方法里面对selector不停循环扫描,如果发现注册channal里面有OP_ACCEPT或READ事件发生,有话就触发一个selector附带上事件处理对象线程,处理完毕之后须将所有注册事件清空,代码如下:
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 ex) {       
}
}

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

6、我们可以在ServerSocketChannal注册sk里附带下面事件处理类对象(注意这是一个内部类):
class Acceptor implements Runnable {
public void run() {
try {
SocketChannel c = serverSocket.accept();
if (c != null)
//调用Handler来处理channel
new SocketReadHandler(selector, c);
}
catch(IOException ex) {     
}
}
}

7、SocketChannelattach功能将Hanlder和可能会发生事件channel链接在一起,当发生事件时,可以立即触发相应 链接Handler。我们在事件处理类里面需要做事情是在selector里面注册socketChannal,并附带上本handler,下一步有 事件触发时会调用本类run方法:
public class SocketReadHandler implements Runnable { 
final SocketChannel socket;    
final SelectionKey sk;
static final int READING = 0, SENDING = 1;  

  public SocketReadHandler(Selector sel, SocketChannel c)
throws IOException {
socket = c;
socket.configureBlocking(false);
sk = socket.register(sel, READING);
sk.attach(this);

    //将SelectionKey注册为可读,以便读取。
sk.interestOps(SelectionKey.OP_READ);
sel.wakeup();
}

  public void run() {
try{    
readRequest() ;
}catch(Exception ex){    
}
}

private void readRequest() throws Exception {
ByteBuffer input = ByteBuffer.allocate(1024);  
try{
int bytesRead = socket.read(input);
......

    //使用线程池处理request
requestHandle(new Request(socket,btt));
.....

  }catch(Exception e) {
}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值