网易云课堂-微专业Java

Netty学习笔记(一)

Netty线程模型

Java NIO虽然为开发者提供了功能强大的IO处理API,但是实际运用中去使用这样的API是比较繁琐的,而且如果抛开多线程技术,程序则无法达到高性能的指标。
Reactor模型将NIO和多线程结合,实现程序高性能。

  • 实现Reactor模型
 private ServerSocketChannel serverSocketChannel;
    // 1、创建多个线程 - accept处理reactor线程 (accept线程)
    private ReactorThread[] mainReactorThreads = new ReactorThread[1];
    // 2、创建多个线程 - io处理reactor线程  (I/O线程)
    private ReactorThread[] subReactorThreads = new ReactorThread[8];

在开源社区中,有很多对JDK NIO进行了封装的十分优秀的网络编程框架,其中应用较高的就有Netty。为了让NIO处理更好的利用多线程特性,Netty实现了Reactor线程模型。

  • Netty结构图

Netty结构图
可以看出Netty主要包括三个部分:左上方红色区域表示支持Socket等多种传输方式;右上方表示提供了多种协议编解码实现;下方表示核心设计,主要包括事件处理模型、API使用、ByteBuffer增强等。

  • Netty实现Reactor线程模型与上代码直接使用线程不同的是其是采用事件轮询机制。
        // 创建EventLoopGroup   accept线程组 NioEventLoop
        EventLoopGroup mainGroup = new NioEventLoopGroup(1);
        // 创建EventLoopGroup   I/O线程组
        EventLoopGroup subGroup2 = new NioEventLoopGroup(1);
        // 服务端启动引导工具类
            ServerBootstrap b = new ServerBootstrap();
            // 配置服务端处理的reactor线程组以及服务端的其他配置
            b.group(mainGroup, subGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)
                    .handler(new LoggingHandler(LogLevel.DEBUG)).childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline p = ch.pipeline();
                    p.addLast(new EchoServerHandler());
                }
            });

ServerBootstrap是Netty服务服务启动类。
group中的parent Group负责处理accept请求,child Group则负责处理具体的业务实现。
channel用于创建具体的通道实例,传入NIOServerChannel。
handler是用来处理服务端通道请求的。
childHandler是用来处理具体socket连接后的请求。
pipeline是责任链(后续学习)。

  • Reactor线程实现:多个请求同时达到服务端,EventLoop开始事件轮询,然后通过Dispatcher分发给各个时间处理器去处理具体的业务实现。
    Reactor线程模型实现
    在这里插入图片描述
    上图中采用了两组不同的EventLoop处理不同通道的不同事件。Main EventLoopGroup主要轮询accept事件,然后将不同请求分发至SubEventLoopGroup中进行具体的I/O处理。

浅看new NioEventLoopGroup源码

  • 创建NioEventLoopGroup的时候,默认线程数是cpu数量*2,也可以显式指定线程数。
 static {
        DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
                "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));

        if (logger.isDebugEnabled()) {
            logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
        }
    }

    /**
     * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor, Object...)
     */
    protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
        //默认是CPU数*2
    }
  • 当调用excutor方法提交任务时,则会判断是否启动,未启动时则调用内置的excutor创建新线程来触发run方法执行

在这里插入图片描述
在这里插入图片描述

  • 创建多个NioEventLoop,形成NioEventLoopGroup
    在这里插入图片描述

  • newChild是NioEventLoop的实现
    在这里插入图片描述
    NioEventLoop具体完成哪些事情呢?

  • 将通道注册到EventLoop的selector上,进行事件轮轮询
    在这里插入图片描述

  • 一步一步查看NioEventLoop父类,发现其最终继承Exector类。在SingleThreadEventExecute类中实现execute方法。
    在这里插入图片描述

  • 执行run方法
    在这里插入图片描述

  • 查看NioEventLoop中的run方法实现,其执行网络处理(selector)
    在这里插入图片描述

  • 点击查看processSelectedKeys(),一步一步查看,查看到根据某个事件类型进行操作的代码
    在这里插入图片描述
    – 注意ServerSocketChannel用的是NioMessageUnsafe,SocketChannel用的是NioByteUnsafe
    –EventLoop的启动
    EventLoop自身实现了Excutor接口,当调用excutor方法提交任务时,则会判断是否启动,未启动时则调用内置的excutor创建新线程来触发run方法执行。

服务端启动

            // 通过bind启动服务
            ChannelFuture f = b.bind(PORT).sync();
            // 阻塞主线程,知道网络服务被关闭
            f.channel().closeFuture().sync();

bind是创建通道,绑定端口。

浅看bind源码

在这里插入图片描述

  • 初始化(selector在之前创建的eventLoop中)
    在这里插入图片描述
  • 查看register方法

在这里插入图片描述

  • 找到相应的register方法。(当子类找不到合适的方法时,就去父类中找)
    在这里插入图片描述
  • 在AbstractChannel.java中unsafe()返回一个unsafe对象
    在这里插入图片描述
  • 在构造函数中会将一个Unsafe对象赋值给unsafe变量
    在这里插入图片描述
  • AbstractNioMessageChannel.java中newUnsafe()中返回一个NioMessageUnsafe
    在这里插入图片描述
  • Unsafe().register()调用的是AbstractChannel中的register方法
    在这里插入图片描述
  • register0()中调用doRegister()方法
    在这里插入图片描述
  • doRegister方法将通道注册到selector中
    在这里插入图片描述
  • 绑定端口
    在这里插入图片描述
  • bind0方法
    在这里插入图片描述
  • bind具体实现
    在这里插入图片描述

至此,netty服务端服务就启动完成。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值