Reactor模型

Reactor是一种设计模式。基于事件驱动,然后通过事件分发器,将事件分发给对应的处理器进行处理。

    Reactor:监听网络端口,分发网络连接事件给Acceptor,具体的感兴趣读写事件handler
    Acceptor:接受新的连接,连接的读写事件操作交给相应的Handler
    Handler:注册为callback对象,并且注册自己感兴趣的读事件或者写事件等等,然后再相应的方法内进行业务操作内容

1.单线程版

参考代码:

package com.ddcx.utils;

/**
 * @author: xc
 * @ClassName: Test
 * @Date: 2021-03-03 12:47
 * @Description:
 */

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

class Reactor implements Runnable {
    final Selector selector;
    final ServerSocketChannel serverSocket;

    Reactor(int port) throws IOException { //Reactor初始化
        selector = Selector.open();
        serverSocket = ServerSocketChannel.open();
        //要监听的网络端口号
        serverSocket.socket().bind(new InetSocketAddress(port));
        //非阻塞
        serverSocket.configureBlocking(false);
        //分步处理,第一步,接收accept事件
        SelectionKey sk =
                serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        //attach callback object, Acceptor
        sk.attach(new Acceptor());
    }

    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                //阻塞到至少有一个通道在你注册的事件上就绪了。 
                selector.select();
                Set selected = selector.selectedKeys();
                Iterator it = selected.iterator();
                while (it.hasNext()) {
                    //Reactor负责dispatch收到的事件
                    dispatch((SelectionKey) (it.next()));
                }
                selected.clear();
            }
        } catch (IOException ex) { /* ... */ }
    }

    void dispatch(SelectionKey k) {
        Runnable r = (Runnable) (k.attachment());
        //调用之前注册的callback对象
        if (r != null) {
            //这里是Acceptor的run方法
            r.run();
        }
    }

    // inner class
    class Acceptor implements Runnable {

        @Override
        public void run() {
            try {
                //阻塞到获取网络连接通道
                SocketChannel channel = serverSocket.accept();
                if (channel != null) {
                    //连接已经就绪,将相应的感兴趣的读写事件注册到回调中
                    new ReadHander(selector, channel);
                }
            } catch (IOException ex) { /* ... */ }
        }
    }


    public static void main(String[] args) throws IOException {
        Reactor reactor = new Reactor(9000);
        reactor.run();
    }
}


package com.ddcx.utils;

/**
 * @author: xc
 * @ClassName: ReadHander
 * @Date: 2021-03-03 12:48
 * @Description:
 */

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

class ReadHander implements Runnable {
    final SocketChannel channel;
    final SelectionKey sk;
    ByteBuffer input = ByteBuffer.allocate(90);
    ByteBuffer output = ByteBuffer.allocate(400);
    static final int READING = 0, SENDING = 1;
    int state = READING;

    ReadHander(Selector selector, SocketChannel c) throws IOException {
        channel = c;
        c.configureBlocking(false);
        // Optionally try first read now
        sk = channel.register(selector, 0);

        //将Handler作为callback对象
        sk.attach(this);

        //第二步,注册Read就绪事件
        sk.interestOps(SelectionKey.OP_READ);
        selector.wakeup();
    }

    boolean inputIsComplete() {
        /* ... */
        return false;
    }

    boolean outputIsComplete() {

        /* ... */
        return false;
    }

    void process() {
        /* ... */
        return;
    }

    @Override
    public void run() {
        try {
            if (state == READING) {
                read();
            } else if (state == SENDING) {
                send();
            }
        } catch (IOException ex) { /* ... */ }
    }

    void read() throws IOException {
        channel.read(input);
        if (inputIsComplete()) {
            process();
            state = SENDING;
            // Normally also do first write now
            //第三步,接收write就绪事件
            sk.interestOps(SelectionKey.OP_WRITE);
        }
    }

    void send() throws IOException {
        channel.write(output);

        //write完就结束了, 关闭select key
        if (outputIsComplete()) {
            sk.cancel();
        }
    }
}

①.通过Selector的select()方法可以选择已经准备就绪的通道

②.通过ServerSocketChannel.accept()方法监听新进来的连接。当accept()方法返回的时候,它返回一个包含新进来的连接的SocketChannel。因此, accept()方法会一直阻塞到有新连接到达。通常不会仅仅只监听一个连接

单线程版 Reactor模型,其实就是做了一件事情,就是把要监听的socket端口注册到selector中去,并且轮询线程内可以获取到多个已经准备就绪的socket连接通道,同时进行处理这些事件

 

2. 多线程Reactor模型

多线程主要体现在handler处理的时候,因为处理的事件可能耗时相对于久一些,这样做可以更快的处理感兴趣的事件

selectionKey.attach(new HandlerThreadPool(socketChannel));

3.主从模式多线程

1. mainReactor负责监听socket连接,用来处理新连接的建立和就绪,将建立的socketChannel指定注册给subReactor。网络连接的建立一般很快,所以这里一个主线程就够了

2.subReactor 一般是cpu的核心数,将连接加入到连接队列进行监听,并创建handler进行各种事件处理;当有新事件发生时, subreactor 就会调用对应的handler处理,而对具体的读写事件业务处理的功能交给handler线程池来完成。

 

### Java Reactor 模型概述 Java 中的 Reactor 模型是一种用于高效处理 I/O 操作的设计模式,特别适用于高并发场景下的网络编程。该模型的核心思想是通过事件驱动的方式管理输入/输出操作,从而提高系统的响应速度和资源利用率。 #### 主要组件 - **Reactor**: 负责监听并分发各种类型的I/O事件给相应的处理器。 - **Handlers (处理器)**: 接收来自Reactor分配的任务,并执行具体的业务逻辑处理[^1]。 #### 三种常见的 Reactor 实现方式 ##### 单 Reactor 单线程模型 在这种最简单的配置下,整个应用程序运行在一个单独的工作线程上,此线程负责所有的读写以及接受新的连接请求等工作。尽管简单易懂,但在面对大量并发访问时性能会受到极大限制。 ##### 单 Reactor 多线程模型 为了克服单线程带来的局限性,在这种设计里引入了一个专门用来接收新连接的Acceptor线程加上一组工作线程池来异步地完成实际的数据传输任务。这种方式能够在一定程度上缓解CPU瓶颈问题的同时保持较好的吞吐量表现[^2]。 ##### 主从 Reactor 多线程模型 进一步优化后的方案采用了更加复杂的架构—即存在一个主Reactor实例(Boss)仅专注于侦听端口上的入站TCP握手消息;而若干个子Reactor对象(Workers),它们各自拥有独立的选择器用于监控已建立好的通信链路状态变化情况。这样的分工协作机制不仅有助于分散负载压力而且提高了整体稳定性与可扩展性[^3]。 ### Netty 的 Reactor 应用案例 Netty 是一款基于 NIO 构建高性能网络应用框架的成功典范之一,其内部正是运用了上述提到过的第三种改进版 Reactor 设计思路: 当一个新的客户端发起连接请求时,`BossGroup` 将接管这个过程直至成功建立起双向数据交换通道为止;随后再把后续可能发生的任何交互活动交由 `WorkerGroups` 来具体实施。每个 worker 都会在自己的事件循环内等待特定条件触发以便及时作出反应,比如接收到对方发送过来的信息包或是本地准备好了待发出的内容等等[^4]。 ```java EventLoopGroup bossGroup = new NioEventLoopGroup(); // 创建 Boss 线程组 EventLoopGroup workerGroup = new NioEventLoopGroup(); // 创建 Worker 线程组 try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) // 使用 NIO 类型的服务端 Channel .childHandler(new ChannelInitializer<SocketChannel>() { // 设置管道初始化器 @Override public void initChannel(SocketChannel ch) throws Exception { Pipeline p = ch.pipeline(); p.addLast(new MyHandler()); // 添加自定义 Handler 进行业务处理 } }); // 绑定端口号并启动服务器 ChannelFuture f = b.bind(PORT).sync(); System.out.println("Server started and listening on " + PORT); // 等待服务关闭 f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值