Reactor 模式简单实现

在网上有部分文章在描述Netty时,会提到Reactor。这个Reactor到底是什么呢?为了搞清楚Reactor到底是什么鬼,我写了一个简单的Demo,来帮助大家理解他。

网上是这么描述Reactor的:

The Reactor design pattern handles service requests that are delivered concurrently to an application by one or more clients.

Each service in an application may consist of serveral methods and is represented by a separate event handler that is responsible for dispatching service-specific requests.

Dispatching of event handlers is performed by an initiation dispatcher, which manages the registered event handlers. Demultiplexing of service requests is performed by a synchronous event demultiplexer.

大致意思是:Reactor是用于处理多个客户端的请求的设计模式。应用程序提供的每一种服务都可能包括多个方法,并且有必要为这每一个服务分配独立的请求处理器(也可以说是 event handler)。对于Event handler的调度是有Dispatcher来执行的,这个Dispatcher可以管理event handler的注册工作。而分离器Demultiplexer则将一个服务分成了多份。这段话看起来还是不那么容易理解的。

我对这段话的理解是:应用程序提供多种服务,而每一种服务都会分为多步骤(或者多类别)进行。这里将每一步都作为一个事件,那么每一步的处理就认为是一个event handler。Dispatcher管理这多个步骤的处理器,也即dispatcher管理着多个Event Handler。而将一个服务处理分为多步骤(多个类别)的处理的工作则是有分离器来完成。

从这个类图上看,主要有四个角色:

·Handle:事件源。

·EventHandler:事件处理器

·Dispatcher:调度器。使用Demultiplexer选出可以执行处理的EventHandler,然后执行对EventHandler的调度。

·Demultiplexer:同步的事件分离器。

从类图上看:Dispatcher中有一个Selector和一个EventHandler集合(可以是List,也可以是Map,具体怎么实现根据实际需求)。Regist_handler、remove_handler用于管理EventHandler。

Handle_events用于启动调度,这个方法的实现通常是:使用分离器选择出可以调度的Event,然后对它们进行调度。

下面就是对Reactor模式的简单实现:

package com.fjn.jdk.nio.reactor.standard;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;

public class StandardReactor {

}

class EventDispatcher {
    Map<EventType, EventHandler> eventHandlerMap = new ConcurrentHashMap<EventType, EventHandler>();

    Demultiplexer selector;

    EventDispatcher(Demultiplexer selector) {
        this.selector = selector;
    }

    public void registEventHandler(EventType eventType, EventHandler eventHandler) {
        eventHandlerMap.put(eventType, eventHandler);

    }

    public void removeEventHandler(EventType eventType) {
        eventHandlerMap.remove(eventType);
    }

    public void handleEvents() {
        dispatch();
    }

    private void dispatch() {
        while (true) {
            List<Event> events = selector.select();

            for (Event event : events) {
                EventHandler eventHandler = eventHandlerMap.get(event.type);
                eventHandler.handle(event);
            }
        }
    }
}

class Demultiplexer {
    private BlockingQueue<Event> eventQueue = new LinkedBlockingQueue<Event>();
    private Object lock = new Object();

    List<Event> select() {
        return select(0);
    }

    List<Event> select(long timeout) {
        if (timeout > 0) {
            if (eventQueue.isEmpty()) {
                synchronized (lock) {
                    if (eventQueue.isEmpty()) {
                        try {
                            lock.wait(timeout);
                        } catch (InterruptedException e) {
                            // ignore it
                        }
                    }
                }

            }
        }
        List<Event> events = new ArrayList<Event>();
        eventQueue.drainTo(events);
        return events;
    }

    public void addEvent(Event e) {
        boolean success = eventQueue.offer(e);
        if (success) {
            synchronized (lock) {
                lock.notify();
            }

        }
    }

}

class Source {
    private Date date = new Date();
    private String id = date.toString() + "_" + System.identityHashCode(date);

    @Override
    public String toString() {
        return id;
    }
}

enum EventType {
    ACCEPT, READ, WRITE, TIMEOUT;
}

class Event {
    public EventType type;
    public Source source;
}

abstract class EventHandler {
    Source source;

    public abstract void handle(Event event);

    public Source getSource() {
        return source;
    }
}

class AcceptEventHandler extends EventHandler {

    private Demultiplexer selector;

    public AcceptEventHandler(Demultiplexer selector) {
        this.selector = selector;
    }

    @Override
    public void handle(Event event) {
        if (event.type == EventType.ACCEPT) {

            Event readEvent = new Event();
            readEvent.source = event.source;
            readEvent.type = EventType.READ;

            selector.addEvent(readEvent);
        }
    }

}

class ReadEventHandler extends EventHandler {
    // private Pipeline pipeline;

    @Override
    public void handle(Event event) {
        // create channel with a pipeline
        // register the channel to this event dispatcher or a child event dispatcher 

        // handle event use the pipeline :
        // step 1:  read to a frame buffer
        // step 2:  use frame decoder to decode buffer as a message (maybe a business object)
        // step 3:  handle the message or submit the message to business thread pool
        // step 4:  register a message event

    }

} 

class WriteEventHandler extends EventHandler {

    @Override
    public void handle(Event event) {
        // step 1: encode a message to byte[]
        // step 2: submit a write task to IOWorker thread pool
    }

}

//-------------------------------分割线--------------------------//

class Acceptor implements Runnable {
    private int port; // server socket port
    private Demultiplexer selector;

    // 代表 serversocket
    private BlockingQueue<Source> sourceQueue = new LinkedBlockingQueue<Source>();

    Acceptor(Demultiplexer selector, int port) {
        this.selector = selector;
        this.port = port;
    }

    public void aNewConnection(Source source) {
        sourceQueue.offer(source);
    }

    public int getPort() {
        return this.port;
    }

    public void run() {
        while (true) {

            Source source = null;
            try {
                // 相当于 serversocket.accept()
                source = sourceQueue.take();
            } catch (InterruptedException e) {
                // ignore it;
            }

            if (source != null) {
                Event acceptEvent = new Event();
                acceptEvent.source = source;
                acceptEvent.type = EventType.ACCEPT;

                selector.addEvent(acceptEvent);
            }

        }
    }

}

class Server {
    Demultiplexer selector = new Demultiplexer();
    EventDispatcher eventLooper = new EventDispatcher(selector);
    Acceptor acceptor;

    Server(int port) {
        acceptor = new Acceptor(selector, port);
    }

    public void start() {
        eventLooper.registEventHandler(EventType.ACCEPT, new AcceptEventHandler(selector));
        new Thread(acceptor, "Acceptor-" + acceptor.getPort()).start();
        eventLooper.handleEvents();
    }

}

Reactor 模式的简单实现的更多相关文章

  1. Reactor模式的.net版本简单实现--DEMO

    近期在学习DotNetty,遇到不少的问题.由于dotnetty是次netty的.net版本的实现.导致在网上叙述dotnetty的原理,以及实现技巧方面的东西较少,这还是十分恼人的.在此建议学习和使 ...

  2. NIO及Reactor模式

    关于Nio Java NIO即Java Non-blocking IO(Java非阻塞I/O),是Jdk1.4之后增加的一套操作I/O工具包,又被叫做Java New IO. Nio要去解决的问题 N ...

  3. Java进阶(五)Java I/O模型从BIO到NIO和Reactor模式

    原创文章,同步发自作者个人博客,http://www.jasongj.com/java/nio_reactor/ Java I/O模型 同步 vs. 异步 同步I/O 每个请求必须逐个地被处理,一个请 ...

  4. ACE - Reactor模式源码剖析及具体实现(大量源码慎入)

    原文出自http://www.cnblogs.com/binchen-china,禁止转载. 在之前的文章中提到过Reactor模式和Preactor模式,现在利用ACE的Reactor来实现一个基于 ...

  5. Reactor模式详解

    转自:http://www.blogjava.net/DLevin/archive/2015/09/02/427045.html 前记 第一次听到Reactor模式是三年前的某个晚上,一个室友突然跑过 ...

  6. reactor模式学习

    一.介绍reactor模式 二.使用reactor模式 三.参考 http://blog.csdn.net/swordmanwk/article/details/6170995  该文章,简单介绍了r ...

  7. IO复用(Reactor模式和Preactor模式)——用epoll来提高服务器并发能力

    上篇线程/进程并发服务器中提到,提高服务器性能在IO层需要关注两个地方,一个是文件描述符处理,一个是线程调度. IO复用是什么?IO即Input/Output,在网络编程中,文件描述符就是一种IO操作 ...

  8. Reactor模式解析——muduo网络库

    最近一段时间阅读了muduo源码,读完的感受有一个感受就是有点乱.当然不是说代码乱,是我可能还没有完全消化和理解.为了更好的学习这个库,还是要来写一些东西促进一下. 我一边读一边尝试在一些地方改用c+ ...

  9. Reactor模式

    对象行为类的设计模式,对同步事件分拣和派发.别名Dispatcher(分发器) Reactor模式是处理并发I/O比较常见的一种模式,用于同步I/O,中心思想是将所有要处理的I/O事件注册到一个中心I ...

随机推荐

  1. 敏捷团队中的QA由来

    QA,全称为Quality Analyst,即质量分析师(有些称为Quality Assurance,即质量保证师).为什么它总跟质量扯在一块?感觉这个角色明明做的都是测试的事情,为什么不直接叫做te ...

  2. exportfs 入门/ 错误

    exportfs -uv 不能卸载, exportfs -au 才可以 ================================================================ ...

  3. Oracle数据库自动备份SQL文本:Procedure存储过程,View视图,Function函数,Trigger触发器,Sequence序列号等

    功能:备份存储过程,视图,函数触发器,Sequence序列号等准备工作:--1.创建文件夹 :'E:/OracleBackUp/ProcBack';--文本存放的路径--2.执行:create or ...

  4. SQL Server 即时文件初始化

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 基础知识(Rudimentary Knowledge) 实现过程(Process) 疑问(Qu ...

  5. 一起学微软Power BI系列-使用技巧(2)连接Excel数据源错误解决方法

    上一篇文章一起学微软Power BI系列-使用技巧(1)连接Oracle与Mysql数据库中,我们介绍了Power BI Desktop中连接Oracle和Mysql的方法,其实说到底还是驱动的问题, ...

  6. ASP.NET Core的配置(5):配置的同步[设计篇]

    本节所谓的"配置同步"主要体现在两个方面:其一,如何监控配置源并在其变化的时候自动加载其数据,其目的是让应用中通过Configuration对象承载的配置与配置源的数据同步:其二. ...

  7. 为什么基于Windows Server 2008 R2的网络负载均衡(NLB)配置的时候总会报错“主机不可访问”?

    配置基于Windows的网络负载均衡是很容易的,操作也很简单,点点鼠标基本上就能完成,但是在进行节点(真实服务器)操作的过程中有时候会遇到一些主机不可访问的报错信息.这个又是为什么呢? Figure ...

  8. linux内核调试技术之修改内核定时器来定位系统僵死问题

    1.简介 在内核调试中,会经常出现内核僵死的问题,也就是发生死循环,内核不能产生调度.导致内核失去响应.这种情况下我们可以采用修改系统内核中的系统时钟的中断来定位发生僵死的进程和函数名称.因为内核系统 ...

  9. ChatSecure

    ChatSecure是一个免费和开源消息传递应用程序的特性 OTR加密在 XMPP. 你可以连接到现有的谷歌帐户或创建新帐户 公共XMPP服务器(包括通过 Tor),甚至 连接到您自己的服务器额外的安 ...

  10. c#面向对象基础技能——学习笔记(二)基于OOP思想研究对象的【属性】

    字段(成员变量): 字段只能从对象中访问实例字段,无法直接从类中访问(换言之,不创建实例就不能访问),可以理解为:字段一般用在内部数据交互使用,当需要为外部提供数据时,(要优先使用自动实现的属性而不是 ...