Netty源码------NioEventLoop源码详解

Netty源码------NioEventLoop

目录

Netty源码------NioEventLoop

1、初识 NioEventLoop 

2、NioEventLoop创建

3、NioEventLoop启动

4、NioEventLoop执行过程

5、 Netty 解决JDK 空轮询Bug

6、总结


1、初识 NioEventLoop 

1.1 先来简单回顾一下Netty模型

  • Netty中的Channel系列类型,对应于经典Reactor模型中的client, 封装了用户的通讯连接。
  • Netty中的EventLoop系列类型,对应于经典Reactor模型中的Reactor,完成Channel的注册、轮询、分发。
  • Netty中的Handler系列类型,对应于经典Reactor模型中的Handler,不过Netty中的Handler设计得更加的高级和巧妙,使用了Pipeline模式。

为了简单了解,来个对比吧:

1、单线程模型,来看下面的应用代码:
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
ServerBootstrap server = new ServerBootstrap();
server.group(bossGroup);
2、多线程模型,再来看下面的应用代码:
EventLoopGroup bossGroup = new NioEventLoopGroup(128);
ServerBootstrap server = new ServerBootstrap();
server.group(bossGroup);
3、主从线程模型,到这里相信大家都已经想到了, 实现主从线程模型的代码如下:
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup);

bossGroup 为主线程,而 workerGroup 中的线程是 CPU 核心数乘以 2,因此对应的到 Reactor 线程模型中,我们知

道, 这样设置的 NioEventLoopGroup 其实就是 Reactor 主从多线程模型。

1.2 再来了解一下NioEventLoop 和本地Selector的对应关系

NioEventLoop类型绑定了两个重要的java本地类型:一个线程类型,一个Selector类型。本地Selector属性的作用,用于注册Java本地channel。本地线程属性的作用,主要是用于轮询。

wps565F.tmp

 

1.3 NioEventLoopGroup与NioEventLoop的关系

下面这张图其实是对Netty中NioEventLoop执行的流程图:

  • 从里面可以知道,NioEventLoop就是在NioEventLoopGroup中创建的,一个NioEventLoopGroup可以包含多个NioEventLoop。
  • 它会在Channel注册完之后,调用run()开始工作。详细的内容,下面介绍:

下面进入源码分析: 

2、NioEventLoop创建

从我们常写的代码入手:

public void start() {
		init();

		//Netty封装了NIO,Reactor模型,Boss,worker
		// Boss线程
		EventLoopGroup bosGroup = new NioEventLoopGroup();
		//worker工作线程
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			//相当于Nio中的ServerSocketChannel
			ServerBootstrap server = new ServerBootstrap();
			//开始设置各种参数
			server.group(bosGroup, workerGroup)
					//主线程处理类
					.channel(NioServerSocketChannel.class)
					//子线程处理类Handler
					.childHandler(new ChannelInitializer<SocketChannel>() {
						protected void initChannel(SocketChannel client) throws Exception {
							//这里采用了责任链模式进行
							client.pipeline().addLast(new HttpResponseEncoder()) //编码器
									.addLast(new HttpRequestDecoder())    //解码器
									.addLast(new GPTomcatHandler());     //业务逻辑处理
						}
					})
					.option(ChannelOption.SO_BACKLOG, 64)  //针对主线程的配置,分配线程最大数量
					.childOption(ChannelOption.SO_KEEPALIVE, true); //针对子线程的配置,保吃长连接
			//启动服务,绑定端口,异步
			ChannelFuture future = server.bind(port).sync();
			System.out.println("GP Tomcat 已启动,监听的端口是:" + port);
			future.channel().closeFuture().sync();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			//关闭线程池
             bosGroup.shutdownGracefully();
             workerGroup.shutdownGracefully();
		}
	}

从new NioEventLoopGroup() 开始跟踪,我们会依次得到下面的代码:

public NioEventLoopGroup() {
        this(0);
}

public NioEventLoopGroup(int nThreads) {
        this(nThreads, (Executor) null);
}

//线程组默认线程数为2倍的cpu数
//DEFAULT_EVENT_LOOP_THREADS=2*Runtime.getRuntime().availableProcessors()
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
    super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}

#MultithreadEventExecutorGroup类,核心方法
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
        if (nThreads <= 0) {
            throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
        }

        if (executor == null) {
            //线程创建器,负责创建NioEventLoopGroup对应底层线程
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }

        children = new EventExecutor[nThreads];//创建NioEventLoop对象数组

        for (int i = 0; i < nThreads; i ++) {
            boolean success = false;
            try {
                //for循环创建每个NioEventLoop,调用newChild(),配置NioEventLoop核心参数
                children[i] = newChild(executor, args);//newChild
                success = true;
            } catch (Exception e) {
                // TODO: Think about if this is a good exception type
                throw new IllegalStateException("failed to create a child event loop", e);
            } finally {
                if (!success) {
                    for (int j = 0; j < i; j ++) {
                        children[j].shutdownGracefully();
                    }

                    for (int j = 0; j < i; j ++) {
                        EventExecutor e = children[j];
                        try {
                            while (!e.isTerminated()) {
                                e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
                            }
                        } catch (InterruptedException interrupted) {
                            // Let the caller handle the interruption.
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                }
            }
        }
        //线程选择器,给每个新连接分配NioEventLoop线程
        chooser = chooserFactory.newChooser(children);

      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值