NioEventLoop源码分析

前置芝士

需要知道Executor执行器的一些操作。(转载请联系)😉

Demo

public class NettyServer {
   
    int port;

    public NettyServer(int port) {
   
        this.port = port;
    }

    public void start() {
   
        ServerBootstrap bootstrap = new ServerBootstrap();
        EventLoopGroup boss = new NioEventLoopGroup(1);
        EventLoopGroup work = new NioEventLoopGroup();
        try {
   
            bootstrap.group(boss, work)
                    .handler(new LoggingHandler(LogLevel.DEBUG))
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChatRoomServerInitializer());

            ChannelFuture f = bootstrap.bind(new InetSocketAddress(port)).sync();
            System.out.println("http server started. port : " + port);
            f.channel().closeFuture().sync();
        } catch (Exception e) {
   
            e.printStackTrace();
        } finally {
   
            boss.shutdownGracefully();
            work.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
   
        NettyServer server = new NettyServer(8080);// 8080为启动端口
        server.start();
    }
}

上面是一段比较简单的Netty服务端的代码,我们主要关注:

EventLoopGroup boss = new NioEventLoopGroup(1); // 用于新连接接入的Group,初始化为1
EventLoopGroup work = new NioEventLoopGroup(); // 用于处理channel中的io事件以及任务的group

NioEventLoopGroup初始化过程

跟进到上述构造函数中,最后会来到MultithreadEventLoopGroup 类中的构造函数:

protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
   
  super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}

传入的参数就是指定Group的大小,默认大小 DEFAULT_EVENT_LOOP_THREADSRuntime.getRuntime().availableProcessors() * 2 也就是两倍的CPU数。

继续跟会来到:

# MultithreadEventExecutorGroup.java
    protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
   
        if (nThreads <= 0) {
   
            throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
        }
				// 这个executor是group所包含的executor,其将来会为其所包含的每个eventLoop创建一个线程
        if (executor == null) {
   
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }

        children = new EventExecutor[nThreads];

        for (int i = 0; i < nThreads; i ++) {
   
            boolean success = false;
            try {
   
              	// 创建eventLoop
                children[i] = newChild(executor, args);
                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 {
   
              	// 有创建失败的eventLoop就关闭所有之前创建的
                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;
                        }
                    }
                }
            }
        }
				// 创建选择器
        chooser = chooserFactory.newChooser(children);

        final FutureListener<Object> terminationListener = new FutureListener<Object>() {
   
            @Override
            public void operationComplete(Future<Object> future) throws Exception {
   
                if (terminatedChildren.incrementAndGet() == children.length) {
   
                    terminationFuture.setSuccess(null);
                }
            }
        };

        for (EventExecutor e: children) {
   
            e.terminationFuture().addListener(terminationListener);
        }

        Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
        Collections.addAll(childrenSet, children);
        readonlyChildren = Collections.unmodifiableSet(childrenSet);
    }

从类名就可以知道这是多线程的线程组,这里主要完成几件事情:

  • new ThreadPerTaskExecutor() [线程创建器]
  • for(){ new Child() } [构造NioEventLoop]
  • chooserFactory.newChooser() [线程选择器]

线程创建器

先看看名字,是给每个任务创建一个线程的线程创建器,其保存在NioEventGroup中的executor中。主要是为每一个NioEventLoop创建一个对应的线程,1:1。

# ThreadPerTaskExecutor.java
public final class ThreadPerTaskExecutor implements Executor {
   
    private final ThreadFactory threadFactory;

    public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
   
        if (threadFactory == null) {
   
            throw new NullPointerException("threadFactory");
        }
      	// 传入一个线程工厂
        this.threadFactory = threadFactory;
    }

    @Override
    public void execute(Runnable command) {
   
      	// 在执行exector的execute()方法时,调用线程工厂创建线程,并start()
        threadFactory.newThread(command).start();
    }
}

上述代码其实就是初始化NioEventGroup中的executor为一个线程工厂,通过之后调用execute()方法为将来的NioEventLoop创建线程来一一对应。

打住,先来看看NioEventLoop的继承关系:

NioEventLoop继承图.png

可知NioEventLoop本身就是一个单线程的EventExecutor,因此有下面创建线程组数组

children = new EventExecutor[nThreads];

而实例化创建EventLoop在函数newChild()中。

构造NioEventLoop

我们跟进到构造NioEventLoop的函数newChild()

# NioEventLoopGroup.java
    @Override
    protected EventLoop newChild(Executor executor, Object... args) throws Exception {
   
        return new NioEventLoop(this, executor, (SelectorProvider) args[0],
            ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
    }

继续跟来到NioEventLoop的构造函数:

# NioEventLoop.java
    NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
                 SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
   
      	// 父类单线程的构造方法,传入的参数executor是group中的executor
        super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
        if (selectorProvider == null) {
   
            throw new NullPointerException("selectorProvider");
        }
        if (strategy == null) {
   
            throw new NullPointerException("selectStrategy");
        }
        provider = selectorProvider;
        selector = openSelector(); // 创建selector事件轮询器到NioEventLoop上
        selectStrategy = strategy;
    }

先跟进父类的构造方法:

# SingleThreadEventLoop.java
    protected SingleThreadEventLoop(EventLoopGroup parent, Execut
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值