Java高级程序设计

设计模式

Reactor

设计模式

在软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。

--Wikipedia

https://en.wikipedia.org/wiki/Software_design_pattern

设计模式分类

  • 创建型模式:创建对象的同时隐藏创建逻辑的方式
  • 结构型模式:关注类和对象的组合
    • 适配器模式(Adapter)、装饰器模式(Decorator)等
  • 行为型模式:关注对象之间的通信
    • 命令模式(Command)、策略模式(Strategy)、响应者模式(Reactor)等

工厂(方法)模式

https://refactoringguru.cn/design-patterns/factory-method

Reactor pattern

The reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers.

https://en.wikipedia.org/wiki/Reactor_pattern

Reactor 模式核心思想

事件驱动 + 同步非阻塞 I/O

  • 事件驱动:基于事件循环,等待事件发生
  • 同步非阻塞:使用 NIO 的 Selector,单线程处理多个连接
  • 解复用:一个线程处理多个 I/O 操作

优势

  • 高并发:单线程处理大量连接
  • 低资源消耗:避免线程创建和上下文切换
  • 响应及时:事件驱动,快速响应

Reactor 模式核心组件

1. Reactor负责监听和分发事件:

public class Reactor {
    private Selector selector;
    
    public void run() {
        while (true) {
            selector.select();  // 阻塞等待事件
            Set<SelectionKey> keys = selector.selectedKeys();
            for (SelectionKey key : keys) {
                dispatch(key);  // 分发事件
            }
        }
    }
}

2. Handler(处理器)处理具体的事件:

public class Handler implements Runnable {
    private SocketChannel channel;
    
    @Override
    public void run() {
        // 处理读/写事件
        if (key.isReadable()) {
            read();
        } else if (key.isWritable()) {
            write();
        }
    }
}

3. Acceptor(接受器)处理连接建立事件:

public class Acceptor implements Runnable {
    private ServerSocketChannel serverChannel;
    
    @Override
    public void run() {
        SocketChannel channel = serverChannel.accept();
        // 注册到 Reactor
        new Handler(channel).register(selector);
    }
}

源自

An Object Behavioral Pattern for
Demultiplexing and Dispatching Handles for Synchronous Events

by Douglas C. Schmidt

http://www.dre.vanderbilt.edu/~schmidt/PDF/reactor-siemens.pdf

实例

A reference implementation of the Reactor Pattern with Java NIO

A typical server application, such as a web server, needs to process thousands of request concurrently. Therefore, the modern web server needs to meet the following requirements

  • Handling of thousands of connections simultaneously (significant number of connections may be in idle state as well)
  • Handling high latency connections

https://github.com/kasun04/nio-reactor

Reactor Pattern

Reactor pattern provides a way in which we can listen to the events (incoming connections/requests) with a synchronous demultiplexing strategy so that when an incoming event occurs, it is dispatched to a service provider (handler) that can handle this event.

Reactor 模式适用场景

  • 高并发服务器:Web 服务器、游戏服务器
  • I/O 密集型应用:文件服务器、代理服务器
  • 长连接应用:聊天服务器、推送服务
  • 需要低延迟:实时通信、金融交易

不适合的场景

  • CPU 密集型任务:计算密集型应用
  • 简单应用:低并发,传统 BIO 即可
  • 同步阻塞操作:需要等待外部系统响应

如何模拟运行

使用 JMeter 或 Gatling 进行压力测试,验证 Reactor 模式的高并发性能。

扩展阅读

Scalable IO in Java

https://gee.cs.oswego.edu/dl/cpjslides/nio.pdf

Reactor 基础款:单线程 Reactor

特点

  • 单线程:Reactor 和 Handler 都在同一个线程
  • 简单高效:无线程切换开销
  • 适用场景:CPU 密集型任务,快速处理

代码示例

...

public class SingleThreadReactor {
    private Selector selector;
    private ServerSocketChannel serverChannel;
    
    public void start() throws IOException {
        selector = Selector.open();
        serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        serverChannel.bind(new InetSocketAddress(8080));
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        
        while (true) {
            selector.select();
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> it = keys.iterator();
            
            while (it.hasNext()) {
                SelectionKey key = it.next();
                it.remove();
                
                if (key.isAcceptable()) {
                    accept(key);  // 接受连接
                } else if (key.isReadable()) {
                    read(key);    // 读取数据(同步处理)
                }
            }
        }
    }
}

优点:简单、高效、无锁
缺点:一个慢请求会阻塞所有请求

Reactor 时尚款:多线程 Reactor

特点

  • Reactor 单线程:处理连接和事件分发
  • Handler 多线程:业务处理在线程池中执行
  • 适用场景:I/O 密集型任务,需要异步处理

代码示例

public class MultiThreadReactor {
    private Selector selector;
    private ExecutorService workerPool = Executors.newFixedThreadPool(10);
    
    public void start() throws IOException {
        // ... 初始化代码同单线程版本 ...
        
        while (true) {
            selector.select();
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> it = keys.iterator();
            
            while (it.hasNext()) {
                SelectionKey key = it.next();
                it.remove();
                
                if (key.isAcceptable()) {
                    accept(key);
                } else if (key.isReadable()) {
                    // 提交到线程池异步处理
                    workerPool.submit(() -> read(key));
                }
            }
        }
    }
}

优点:业务处理不阻塞事件循环
缺点:线程切换开销,需要线程池管理

Reactor 豪华款:多 Reactor

特点

  • 主 Reactor:处理连接建立(Acceptor)
  • 子 Reactor 池:处理 I/O 事件(多个 Selector)
  • 适用场景:超高并发,需要充分利用多核 CPU

代码示例

public class MultiReactor {
    private Reactor mainReactor;      // 主 Reactor(处理连接)
    private Reactor[] subReactors;     // 子 Reactor 池(处理 I/O)
    private int next = 0;
    
    public MultiReactor(int subReactorCount) {
        mainReactor = new Reactor();  // 主 Reactor
        subReactors = new Reactor[subReactorCount];
        for (int i = 0; i < subReactorCount; i++) {
            subReactors[i] = new Reactor();  // 创建子 Reactor
        }
    }
    
    public void start() throws IOException {
        // 主 Reactor 只处理连接
        mainReactor.registerAccept(serverChannel, (channel) -> {
            // 连接建立后,分配给子 Reactor
            Reactor subReactor = subReactors[next++ % subReactors.length];
            subReactor.register(channel);  // 注册到子 Reactor
        });
        
        // 启动所有 Reactor
        new Thread(mainReactor).start();
        for (Reactor subReactor : subReactors) {
            new Thread(subReactor).start();
        }
    }
}

优点:充分利用多核,高并发性能最佳
缺点:实现复杂,需要负载均衡

三种模式对比

特性 单线程 Reactor 多线程 Reactor 多 Reactor
Reactor 线程数 1 1 N(主+子)
Handler 线程 同线程 线程池 同线程
适用场景 CPU 密集型,快速处理 I/O 密集型,异步处理 超高并发
复杂度
性能 中等 最高

实际应用:Netty