学习 Doug Lea 大神写的——Scalable IO in Java
学习 Doug Lea 大神写的——Scalable IO in Java
网络服务
Web services、分布式对象等等都具有相同的处理结构
- Read request
- Decode request
- Process service
- Encode reply
- Send reply
基础的网络设计

每一个处理的 handler 都在各自的线程中处理。
代码示例
public class Server01 implements Runnable {
@Override public void run() {
try {
ServerSocket serverSocket = new ServerSocket(9898);
while (!Thread.interrupted()) {
// serverSocket.accept() 会阻塞到有客户端连接,之后 Handler 会处理
new Thread(new Handler(serverSocket.accept())).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static class Handler implements Runnable {
private final Socket socket;
Handler(Socket socket) {
this.socket = socket;
}
@Override public void run() {
try {
byte[] input = new byte[1024];
// 假设能全部读取出来
socket.getInputStream().read(input);
byte[] output = process(input);
socket.getOutputStream().write(output);
} catch (Exception e) {
e.printStackTrace();
}
}
private byte[] process(byte[] input) {
// 里面处理逻辑
return new byte[0];
}
}
}
这样做的好处是通过 accept 事件来触发任务的执行,将每个任务单独的去执行。但是缺点也很明显如果客户端链接过大那么需要新建若干个线程去执行,每台服务器可以运行的线程数是有限的。那么多线程的上下文切换的消耗也是巨大的。
Reactor Pattern
首先我们先来看下什么是事件驱动,在 java AWT 包中广泛的得到了使用。用户在点击一个 button 按钮的时候就会触发一个事件,然后会使用观察者模式来触发 Listener 中的处理事件。

Reactor 设计模式是基于事件驱动的一种实现方式,处理多个客户端并发的向服务端请求服务的场景。每种服务在服务端可能由多个方法组成。reactor 会解耦并发请求的服务并分发给对应的事件处理器来处理。目前,许多流行的开源框架都用到了。类似 AWT 中的 Thread。
Handlers 执行非阻塞操作的具体类,类似 AWT 中的 ActionListeners。
Reactor 单线程处理任务的设计

代码示例
public class Reactor implements Runnable {
private final Selector selector;
private final ServerSocketChannel serverSocketChannel;
public Reactor(int port) throws IOException {
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(port));
serverSocketChannel.configureBlocking(false);
SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
selectionKey.attach(new Acceptor());
}
@Override public void run() {
try {
while (!Thread.interrupted()) {
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
for (SelectionKey selectionKey : selectionKeys) {
dispatch(selectionKey);
selectionKeys.clear();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void dispatch(SelectionKey selectionKey) {
Runnable runnable = (Runnable) selectionKey.attachment();
if (null != runnable) {
runnable.run();
}
}
private class Acceptor implements Runnable {
@Override public void run() {
try {
SocketChannel socketChannel = serverSocketChannel.accept();
if (null != socketChannel) {
new Handler(selector, socketChannel);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private class Handler implements Runnable {
private final SocketChannel socketChannel;
private final SelectionKey selectionKey;
private ByteBuffer input = ByteBuffer.allocate(1024);
private ByteBuffer output = ByteBuffer.allocate(1024);
private static final int READING = 0, SENDING = 1;
private int state = READING;
Handler(Selector selector, SocketChannel socketChannel) throws IOException {
this.socketChannel = socketChannel;
this.socketChannel.configureBlocking(false);
selectionKey = this.socketChannel.register(selector, 0);
selectionKey.attach(this);
selectionKey.interestOps(SelectionKey.OP_READ);
selector.wakeup();
}
void process() {
}
@Override public void run() {
try {
if (state == READING) {
socketChannel.read(input);
process();
state = SENDING;
selectionKey.interestOps(SelectionKey.OP_WRITE);
}
if (state == READING) {
socketChannel.write(output);
selectionKey.cancel();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
这个程序的重点在于 selectionKey.attach(); 方法每次把需要的对象传入进去,之后在有事件触发的时候会在 dispatch 中 attachment() 获取到这个对象,之后直接调用 run 方法。
Reactor 多线程处理任务的设计

只需要稍微修改下 Handler 这个类
// 添加一个线程池开发时请使用自定义或 spring 的线程池
private final ExecutorService executorService = Executors.newCachedThreadPool();
// 修改 run 方法
@Override public void run() {
try {
if (state == READING) {
socketChannel.read(input);
executorService.execute(new Runnable() {
@Override public void run() {
process();
state = SENDING;
selectionKey.interestOps(SelectionKey.OP_WRITE);
}
});
}
if (state == READING) {
socketChannel.write(output);
selectionKey.cancel();
}
} catch (Exception e) {
e.printStackTrace();
}
}
多个 Reactor

当看到这幅图的时候感觉这不就是 Netty EventLoopGroup 的工作模式吗
- mainReactor 不就是 bossGroup
- subReactor 不就是 workGroup
至此粗略的看完了这篇文章,感觉太 6 了,需要后面重复学习,这次只是了解大概。后面学习完会持续更新这篇文章!
学习 Doug Lea 大神写的——Scalable IO in Java的更多相关文章
- Netty Reator(二)Scalable IO in Java
Netty Reator(二)Scalable IO in Java Netty 系列目录 (https://www.cnblogs.com/binarylei/p/10117436.html) Do ...
- 【精尽Netty源码解析】1.Scalable IO in Java——多Reactor的代码实现
Java高伸缩性IO处理 在Doug Lea大神的经典NIO框架文章<Scalable IO in Java>中,具体阐述了如何把Reactor模式和Java NIO整合起来,一步步理论结 ...
- 《Scalable IO in Java》译文
<Scalable IO in Java> 是java.util.concurrent包的作者,大师Doug Lea关于分析与构建可伸缩的高性能IO服务的一篇经典文章,在文章中Doug L ...
- 一文弄懂-《Scalable IO In Java》
目录 一. <Scalable IO In Java> 是什么? 二. IO架构的演变历程 1. Classic Service Designs 经典服务模型 2. Event-drive ...
- 《Scalable IO in Java》笔记
Scalable IO in Java http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf 基本上所有的网络处理程序都有以下基本的处理过程:Read reque ...
- Scalable IO in Java
Scalable IO in Java http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf 大部分IO都是下面这个步骤, Most have same basi ...
- 五月的仓颉大神写的 三年java程序员面试感悟 值得分享给大家
感谢 五月的仓颉 的这篇文章 , 让我重新认识到自己身上的不足之处 . 原文地址http://www.cnblogs.com/xrq730/p/5260294.html,转载请注明出处,谢谢! 前 ...
- 学习Python不得不关注和学习的国外大神博客
注意 : 本文收集于网路 . 由于常常更新 , 有些链接打不开, 请自备梯子 在学习Python过程中,总会遇到各种各样的坑, 虽然Python是一门优美而简单易学的语言 . 但当学习后 , 总想着更 ...
- 大神为你分析 Go、Java、C 等主流编程语言(Go可以替代Java,而且最小化程序员的工作量,学习比较容易)
本文主要分析 C.C++98.C++11.Java 与 Go,主要论述语言的关键能力.在论述的过程中会结合华为各语言编程专家和华为电信软件内部的骨干开发人员的交流,摒弃语言偏好或者语言教派之争,尽量以 ...
随机推荐
- excel数据生成sql insert语句
excel数据生成sql insert语句 excel表格中有A.B.C三列数据,希望导入到数据库users表中,对应的字段分别是name,sex,age . 在你的excel表格中增加一列,利用ex ...
- Struts1.3——Struts标签
1.struts标签的介绍 Struts框架提供了一组非常丰富的框架组件,同时也提供了一组标签库用于和这些组件交互,主要介绍以下三类: html标签 bean标签 logic标签 2.Html标签库 ...
- 使用latex绘制多层神经网络结构图
1,使用Tikz包: 2,参考官方例程单层神经网络结构,绘制了一个含有3隐藏层的BP神经网络节点图 代码如下: \documentclass{article} \usepackage{tikz} \b ...
- PHP中使用raw格式发送POST请求
如果请求的参数格式是原生(raw)的内容,应该如何为程序构造一个POST请求函数呢? function http_post($url, $data_string) { $ch = curl_init( ...
- 字母所对应的Unicode编码
A~Z 65~90 a~z 97~122 public class Unicode { public static void main(S ...
- 常用命令--mount
mount -o remount,rw / mount 命令 [-t 文件系统] [-L 卷标名] [-o 特殊选项] 设备文件名 挂载点 -l 查询系统中已经挂载的设备,-l 会显示卷标 -a ...
- Tomcat启动脚本(3)setclasspath.bat
@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor lic ...
- 关于java使用json不能够使用报没有导包的问题,以及前后台交互json数据的使用
博客搬迁,给你带来的不便,敬请谅解! http://www.suanliutudousi.com/2017/12/02/%e5%85%b3%e4%ba%8ejava%e4%bd%bf%e7%94%a8 ...
- JavaScript去除数组中重复的数字
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- Excel解析工具POI
HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls XSSFWorkbook:是操作Excel2007的版本,扩展名是.xlsx 对于不同版本的EXCEL文 ...