`

反应器(Reactor)模式

    博客分类:
  • java
 
阅读更多

概述

Java NIO非堵塞技术实际是采取反应器模式,或者说是观察者(observer)模式为我们监察I/O端口,如果有内容进来,会自动通知我们,这样,我们就不必开启多个线程死等,从外界看,实现了流畅的I/O读写,不堵塞了。

同步和异步区别:有无通知(是否轮询)
堵塞和非堵塞区别:操作结果是否等待(是否马上有返回值),只是设计方式的不同

NIO 有一个主要的类Selector,这个类似一个观察者,只要我们把需要探知的socketchannel告诉Selector,我们接着做别的事情,当有事件发生时,他会通知我们,传回一组SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据,接着我们可以处理这些数据。

反应器模式与观察者模式在某些方面极为相似:当一个主体发生改变时,所有依属体都得到通知。不过,观察者模式与单个事件源关联,而反应器模式则与多个事件源关联 。

一般模型

我们想象以下情形:长途客车在路途上,有人上车有人下车,但是乘客总是希望能够在客车上得到休息。

传统的做法是:每隔一段时间(或每一个站),司机或售票员对每一个乘客询问是否下车。

反应器模式做法是:汽车是乘客访问的主体(Reactor),乘客上车后,到售票员(acceptor)处登记,之后乘客便可以休息睡觉去了,当到达乘客所要到达的目的地后,售票员将其唤醒即可。

 

代码实现

[java] view plain copy
  1. package com.linxcool.reactor;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.InetAddress;  
  5. import java.net.InetSocketAddress;  
  6. import java.nio.channels.SelectionKey;  
  7. import java.nio.channels.Selector;  
  8. import java.nio.channels.ServerSocketChannel;  
  9. import java.util.Iterator;  
  10. import java.util.Set;  
  11.   
  12. /** 
  13.  * 反应器模式 
  14.  * 用于解决多用户访问并发问题 
  15.  *  
  16.  * 举个例子:餐厅服务问题 
  17.  *  
  18.  * 传统线程池做法:来一个客人(请求)去一个服务员(线程) 
  19.  * 反应器模式做法:当客人点菜的时候,服务员就可以去招呼其他客人了,等客人点好了菜,直接招呼一声“服务员” 
  20.  *  
  21.  * @author linxcool 
  22.  */  
  23. public class Reactor implements Runnable{  
  24.     public final Selector selector;  
  25.     public final ServerSocketChannel serverSocketChannel;  
  26.   
  27.     public Reactor(int port) throws IOException{  
  28.         selector=Selector.open();  
  29.         serverSocketChannel=ServerSocketChannel.open();  
  30.         InetSocketAddress inetSocketAddress=new InetSocketAddress(InetAddress.getLocalHost(),port);  
  31.         serverSocketChannel.socket().bind(inetSocketAddress);  
  32.         serverSocketChannel.configureBlocking(false);  
  33.           
  34.         //向selector注册该channel    
  35.         SelectionKey selectionKey=serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);  
  36.   
  37.         //利用selectionKey的attache功能绑定Acceptor 如果有事情,触发Acceptor   
  38.         selectionKey.attach(new Acceptor(this));  
  39.     }  
  40.   
  41.     @Override  
  42.     public void run() {  
  43.         try {  
  44.             while(!Thread.interrupted()){  
  45.                 selector.select();  
  46.                 Set<SelectionKey> selectionKeys= selector.selectedKeys();  
  47.                 Iterator<SelectionKey> it=selectionKeys.iterator();  
  48.                 //Selector如果发现channel有OP_ACCEPT或READ事件发生,下列遍历就会进行。  
  49.                 while(it.hasNext()){  
  50.                     //来一个事件 第一次触发一个accepter线程    
  51.                     //以后触发SocketReadHandler  
  52.                     SelectionKey selectionKey=it.next();  
  53.                     dispatch(selectionKey);  
  54.                     selectionKeys.clear();  
  55.                 }  
  56.             }  
  57.         } catch (IOException e) {  
  58.             e.printStackTrace();  
  59.         }  
  60.     }  
  61.       
  62.     /** 
  63.      * 运行Acceptor或SocketReadHandler 
  64.      * @param key 
  65.      */  
  66.     void dispatch(SelectionKey key) {  
  67.         Runnable r = (Runnable)(key.attachment());    
  68.         if (r != null){    
  69.             r.run();  
  70.         }    
  71.     }    
  72.   
  73. }  
[java] view plain copy
  1. package com.linxcool.reactor;  
  2.   
  3. import java.io.IOException;  
  4. import java.nio.channels.SocketChannel;  
  5.   
  6. public class Acceptor implements Runnable{  
  7.     private Reactor reactor;  
  8.     public Acceptor(Reactor reactor){  
  9.         this.reactor=reactor;  
  10.     }  
  11.     @Override  
  12.     public void run() {  
  13.         try {  
  14.             SocketChannel socketChannel=reactor.serverSocketChannel.accept();  
  15.             if(socketChannel!=null)//调用Handler来处理channel  
  16.                 new SocketReadHandler(reactor.selector, socketChannel);  
  17.         } catch (IOException e) {  
  18.             e.printStackTrace();  
  19.         }  
  20.     }  
  21. }  
[java] view plain copy
  1. package com.linxcool.reactor;  
  2.   
  3. import java.io.IOException;  
  4. import java.nio.ByteBuffer;  
  5. import java.nio.channels.SelectionKey;  
  6. import java.nio.channels.Selector;  
  7. import java.nio.channels.SocketChannel;  
  8.   
  9. public class SocketReadHandler implements Runnable{  
  10.     private SocketChannel socketChannel;  
  11.     public SocketReadHandler(Selector selector,SocketChannel socketChannel) throws IOException{  
  12.         this.socketChannel=socketChannel;  
  13.         socketChannel.configureBlocking(false);  
  14.           
  15.         SelectionKey selectionKey=socketChannel.register(selector, 0);  
  16.           
  17.         //将SelectionKey绑定为本Handler 下一步有事件触发时,将调用本类的run方法。    
  18.         //参看dispatch(SelectionKey key)    
  19.         selectionKey.attach(this);  
  20.           
  21.         //同时将SelectionKey标记为可读,以便读取。    
  22.         selectionKey.interestOps(SelectionKey.OP_READ);    
  23.         selector.wakeup();  
  24.     }  
  25.       
  26.     /** 
  27.      * 处理读取数据 
  28.      */  
  29.     @Override  
  30.     public void run() {  
  31.         ByteBuffer inputBuffer=ByteBuffer.allocate(1024);  
  32.         inputBuffer.clear();  
  33.         try {  
  34.             socketChannel.read(inputBuffer);  
  35.             //激活线程池 处理这些request  
  36.             //requestHandle(new Request(socket,btt));   
  37.         } catch (IOException e) {  
  38.             e.printStackTrace();  
  39.         }  
  40.     }  
  41. }  

 

分享到:
评论

相关推荐

    ACE反应器(Reactor)模式的深入分析

    反应器(Reactor):用于事件多路分离和分派的体系结构模式通常的,对一个文件描述符指定的文件或设备, 有两种工作方式: 阻塞与非阻塞。所谓阻塞方式的意思是指, 当试图对该文件描述符进行读写时, 如果当时没有东西...

    Java Reactor反应器模式使用方法详解

    主要介绍了Java Reactor反应器模式使用方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    Reactor反应器的实现方法详解

    但是你也可以选择自己的反应器,这是因为ACE使用了Bridge模式(使用两个不同的类:一个是编程接口,另一个是实现,第一个类会把各个操作传给第二个类)。例如使用线程池反应器实现:ACE_TP_Reactor* tp_reactor = ...

    C++从0实现百万并发Reactor服务器完结13章

    Reactor 模式也叫做反应器设计模式,它是一种为处理服务请求并发提交到一个或者多个服务处理程序的事件设计模式。当请求抵达后,服务处理程序使用解多路分配策略,然后同步地派发这些请求至相关的请求处理程序。 ...

    C++从0实现百万并发Reactor服务器完结13章下载

    reactor是一种设计模式, 是服务器的重要模型, 是一种事件驱动的反应堆模式, 高效的事件处理模型。 reactor 反应堆: 事件来了才执行,事件类型可能不尽相同,所以我们需要提前注册好不同的事件处理函数。事件到来就...

    Scalable IO in Java.zip

    文章中基于Reactor反应器模式的几种服务模型架构,阅读这篇文章有助于你更深入了解Netty等服务框架的编程思想与设计模式。同时压缩包内还包含reactor-siemens.pdf描述reactor的英文论文,有助于加深reactor模式的...

    ACE技术论文集(已翻译为中文)

    第 7 章 ACE 反应器(Reactor)的设计和使用:用于事件多路分离的面向对象框架 第 8 章 前摄器(Proactor):用于为异步事件多路分离和分派处理器的对象行为模式 第 9 章 接受器-连接器(Acceptor-Connector):...

    ACE学习文档大全.rar

    ACE 入门,ACE中文文档,ACE_Task框架,ACE的框架及其核心,ACE反应器(Reactor)模式,ACE线程管理机制,ACE通用服务端框架,ACE通用客户端框架,ACE中TCP通信

    剖析Python的Twisted框架的核心特性

    就reactor模式的网络IO而言,应该是同步IO而不是异步IO。而Dave第一章中提到的异步,核心在于:显式地放弃对任务的控制权而不是被操作系统随机地停止,程序员必须将任务组织成序列来交替的小步完成。因此,若其中一...

    基于S-x空间反应分离循环系统的最优工艺条件研究 (2010年)

    针对定态、恒温、等容反应过程,将二维...以 Van de Vusse反应模式为例,分析了关键反应物转化率、未反应物的回收率以及产品分离程度对 RSR系 统最大总收率的影响,获得了最佳 CSTR―分离器―循环结构及其最佳工艺条件。

    Linux高性能服务器编程

    第8章 高性能服务器程序框架 8.1 服务器模型 8.1.1 CS模型 8.1.2 P2P模型 8.2 服务器编程框架 8.3 IO模型 8.4 两种高效的事件处理模式 8.4.1 Reactor模式 8.4.2 Proactor模式 8.4.3 模拟Proactor模式 8.5...

Global site tag (gtag.js) - Google Analytics