模型:

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

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

JDK中模式原型复现:

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

首先,仅仅是建立连接(socket),就占用了服务器的线程资源。如果客户端还没有发出相应的数据请求,那么服务器就要一直等待他们的数据流过来,然后再进行读取,如此往复 … … 一直都blocking。服务器处在一个高负荷状态中。

  NIO出来之后,进入改革开放时期,有了这么几个角色,ServerSocketChannel,SelectionKey,Selector

这几个角色都是做什么用的呢?需要了解一下reactor模式(反应堆模式)。作为服务端,如果什么操作都要依赖于客户端,很多操作都阻塞,如上面的代码片段所示。reactor模式提供了一种很好的事件处理机制,以分离事件处理对象与事件之间的耦合。如下图示(详细请看参考资料(1)):

说明:

  Acceptor就是我们Server端的主要任务消化者;

  Initiation Dispatcher是事件(Event)的分发者;

  HTTP Handler是具体操作人。

  ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

首先,在Initiation Dispatcher中注册一个acceptor

(1:register Acceptor),这个Acceptor是跟事件绑定的,它仅仅关心某种事件(event)。Initiation Dispatcher不断地循环获取请求过来的事件

(2:handle events),如果发现有对应Acceptor关心的事件

(3:connect),通知Acceptor有事件发生

(4:new connection)。 Acceptor针对此事件进行处理,创建了新的HTTP Handler

(5:create handler))一轮事件获取和分发完成。

那么handler是不是就抓住这个connection不放,然后一直苦苦等待数据流的到来呢?

  不是的,它也是将自己和自己关心的事件注册到Initiation Dispatcher。如果Initiation Dispatcher在handle Events时发现了它关心的事件,那么就会交由它去进行相应处理。如下图示,在连接完成后,browser提交的get请求,handler的处理过程:

这里面尤其要注意到,2:read ready,之后才read request,也就是说,handler在dispatcher中注册了自己关心的事件(READ),然后在写的时候,也是类似情况。

以上的过程就实现了非阻塞的处理方式,客户端的连接可以非阻塞(这是意思是,acceptor不必一直苦苦等候),然后对客户端过来的request内容,也是非阻塞(这里是不必苦苦等待其数据的到来),都是不必一直眼巴巴的看着那个连接,那些数据,而是如果有我关心的事件了,我再进行处理,期间完全相信Initiation Dispatcher就行了。

这里有一点要注意,就是现在的reactor模式都是建立在操作系统的基础上实现的,不同的操作系统有不同的实现方式。而且都不支持多线程(针对Initiation Dispatcher而言)。

Java-技术专区-设计模式-reactor模式的更多相关文章

  1. 【Java技术位】——代理模式及其事务包

    背景 项目中我们会遇到这种情况:在几个方法中增加同样的代码,这些代码是与业务无关的,而且以后有可能因为考虑不周或需求变动再或者是其它原因,我们须要对他们进行逐一进行修改.举个详细的样例,比方程序中的日 ...

  2. 🏆【Java技术专区】「探针Agent专题」Java Agent探针的技术介绍(1)

    前提概要 Java调式.热部署.JVM背后的支持者Java Agent: 各个 Java IDE 的调试功能,例如 eclipse.IntelliJ : 热部署功能,例如 JRebel.XRebel. ...

  3. 🏆【Java技术专区】「编译器专题」重塑认识Java编译器的执行过程(消除数组边界检查+公共子表达式)!

    前提概要 Java的class字节码并不是机器语言,要想让机器能够执行,还需要把字节码翻译成机器指令.这个过程是Java虚拟机做的,这个过程也叫编译.是更深层次的编译. 在编译原理中,把源代码翻译成机 ...

  4. 🏆【Java技术专区】「开发实战专题」Lombok插件开发实践必知必会操作!

    前言 在目前众多编程语言中,Java 语言的表现还是抢眼,不论是企业级服务端开发,还是 Andorid 客户端开发,都是作为开发语言的首选,甚至在大数据开发领域,Java 语言也能占有一席之地,如Ha ...

  5. Java技术专区-虚拟机系列-类加载机制(类的初始化)

      类加载的生命周期:  加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载       加载 -> 验证 -> 准备 -& ...

  6. Java技术专区-虚拟机系列-虚拟机参数(常用)

    基础参数系类(内存分配) -server:一定要作为第一个参数,在多个CPU时性能佳 -Xmn:young generation的heap大小,一般设置为Xmx的3.4分之一-Xms:初始Heap大小 ...

  7. Java技术专区-虚拟机系列-堆快照(获取)

    1.JVM-堆快照(Snapshot) 1.1 输出方式-获取hprof文件 启动参数配置OOM时触发打印堆快照 (1)tomcat启动方式添加参数 (添加环境变量) export JAVA_OPTS ...

  8. 🏆【Java技术专区】「并发编程专题」教你如何使用异步神器CompletableFuture

    前提概要 在java8以前,我们使用java的多线程编程,一般是通过Runnable中的run方法来完成,这种方式,有个很明显的缺点,就是,没有返回值.这时候,大家可能会去尝试使用Callable中的 ...

  9. 🏆【Java技术专区】「延时队列专题」教你如何使用【精巧好用】的DelayQueue

    延时队列前提 定时关闭空闲连接:服务器中,有很多客户端的连接,空闲一段时间之后需要关闭之. 定时清除额外缓存:缓存中的对象,超过了空闲时间,需要从缓存中移出. 实现任务超时处理:在网络协议滑动窗口请求 ...

随机推荐

  1. etc/pass命令列表

    用户 密码 用户UID 用户组GID 备注 home目录位置 默认shell root x 0 0 root /root /bin/bash daemon x 1 1 daemon /usr/sbin ...

  2. ubuntu14彻底删除mysql!!!(精)

    解决方法: 删除mysql前 先删除一下 /var/lib/mysql 还有 /etc/mysql sudo rm /var/lib/mysql/ -R sudo rm /etc/mysql/ -R ...

  3. bzoj2085 [Poi2010]Hamsters 矩阵快速幂+字符串hash

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2085 题解 考虑暴力 DP 的做法.令 \(dp[i][j]\) 表示以 \(j\) 为开头的 ...

  4. Thinkphp 请求和响应

    一. Request对象获取方法 1. request() 助手函数获取 2. think\Request 类获取 3.利用框架注入Request对象  Request方法时单利方法 在think框架 ...

  5. 【leetcode】403. Frog Jump

    题目如下: 解题思路:我的做法是建立一个字典dic,key为stone,value是一个set,里面存的是从前面的所有stone跳跃到当前stone的unit集合.例如stones=[0,1,2,3] ...

  6. navicat的使用(测试库和正式库同步)以及用plsql改表字段属性

    说明:数据库的操作,除了查询,最好先做好备份,比如数据同步.更新.修改或删除之类的: netstat -antp   查看mysql端口 firewall -cmd --list-all    查看防 ...

  7. JS获取各种宽度、高度的简单介绍:

    JS获取各种宽度.高度的简单介绍: scrollHeight: 获取对象的滚动高度. scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离 scrollTop:设置或获 ...

  8. hud 4347 The Closest M Points(KD-Tree)

    传送门 解题思路 \(KD-Tree\)模板题,\(KD-Tree\)解决的是多维问题,它是一个可以储存\(K\)维数据的二叉树,每一层都被一维所分割.它的插入删除复杂度为\(log^2 n\),它查 ...

  9. 前端通过axios和FormData实现文件上传功能遇到的坑

    使用element-ui中的upload上传组件,前端上传数据参数已经传过去了,但是后端 (java) 接不到数据 (null) [解决方案] html部分: <el-button type=& ...

  10. (转)jupyter常用快捷键

    转:http://www.mamicode.com/info-detail-2395285.html Jupyter Notebook 有两种键盘输入模式.即命令模式和编辑模式,这与 vim有些类似. ...