网络编程与Netty(四) Netty源码-(Ⅵ)

EventLoop系列源码分析

EventLoopGroup 和 EventLoop 代码分析

​ 在刚开始介绍Netty时笔者曾手写过一个Netty的Demo,其实那里面用到了很多常用的组件,并且Netty在使用上代码基本都是那一套,那么这些代码每一行都做了什么事?底层的原理是什么?接下来就一一讲解这段代码的底层运行流程:为了防止大家忘记,这里将代码贴出来

//eventLoop暂时理解为线程组
EventLoopGroup group = new NioEventLoopGroup();
try {
    //ServerBootStrap是启动必备的,启动相关的工作基本都是由它完成的
    ServerBootstrap sb = new ServerBootstrap();
    sb.group(group)
        .channel(NioServerSocketChannel.class)
        .localAddress(new InetSocketAddress(port))
        .childHandler(new ServerChannelInitializer());
    //bind()方法是整个服务启动的一个关键方法,并且同步
    ChannelFuture future = sb.bind().sync();
    future.channel().closeFuture().sync();
}finally {
    group.shutdownGracefully().sync();
}

​ 首先就是EventLoopGroup group = new NioEventLoopGroup(),这里创建的是NioEventLoopGroup,一路查看下来,会执行MultithreadEventLoopGroup的构造函数:

在这里插入图片描述

​ MultithreadEventLoopGroup的构造函数需要关注的是它会判断是否有限制线程数,如果nThreads=0则需要拿到CPU核心数*2来作为线程数,这个构造函数又调用了父类的构造函数super,父类是 MultithreadEventExecutorGroup,所以进入 MultithreadEventExecutorGroup的构造函数看看:

在这里插入图片描述

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) {
        this.terminatedChildren = new AtomicInteger();
        this.terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
        if (nThreads <= 0) {
            throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
        } else {
        //首先会判断executor是否实例化,如果为null则实例化ThreadPerTaskExecutor
        //ThreadPerTaskExecutor这个类有个成员变量TreadFatory,专门new线程的
        //当调用executor的execute方法时才真的创建一个线程,此时还未与EventLoop挂钩
        //要和NioEventLoop的线程挂钩则在SingleThreadEventExecutor的doStartThread方法里
            if (executor == null) {
                executor = new ThreadPerTaskExecutor(this.newDefaultThreadFactory());
            }
		//这个就是存EventExecutor(实际是NioEventLoop)的实例数组,并在循环里new出每个EventLoop实例
            this.children = new EventExecutor[nThreads];
            int j;
            for(int i = 0; i < nThreads; ++i) {
                boolean success = false;
                boolean var18 = false;
                try {
                    var18 = true;
               //这个newChild方法就是调用NioEventLoopGroup的newChild方法来创建NioEventLoop
               //接下来看看这个newChild的实现
                    this.children[i] = this.newChild((Executor)executor, args);
                    success = true;
                    var18 = false;
                } catch (Exception var19) {
                    throw new IllegalStateException("failed to create a child event loop", var19);
                } finally {
                    if (var18) {
                        if (!success) {
                            int j;
                            for(j = 0; j < i; ++j) {
                                this.children[j].shutdownGracefully();
                            }

                            for(j = 0; j < i; ++j) {
                                EventExecutor e = this.children[j];

                                try {
                                    while(!e.isTerminated()) {
                                        e.awaitTermination(2147483647L, TimeUnit.SECONDS);
                                    }
                                } catch (InterruptedException var20) {
                                    Thread.currentThread().interrupt();
                                    break;
                                }
                            }
                        }

                    }
                }

                if (!success) {
                    for(j = 0; j < i; ++j) {
                        this.children[j].shutdownGracefully();
                    }

                    for(j = 0; j < i; ++j) {
                        EventExecutor e = this.children[j];

                        try {
                            while(!e.isTerminated()) {
                                e.awaitTermination(2147483647L, TimeUnit.SECONDS);
                            }
                        } catch (InterruptedException var22) {
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                }
            }

            this.chooser = chooserFactory.newChooser(this.children);
            FutureListener<Object> terminationListener = new FutureListener<Object>() {
                public void operationComplete(Future<Object> future) throws Exception {
                    if (MultithreadEventExecutorGroup.this.terminatedChildren.incrementAndGet() == MultithreadEventExecutorGroup.this.children.length) {
                        MultithreadEventExecutorGroup.this.terminationFuture.setSuccess((Object)null);
                    }

                }
            };
            EventExecutor[] var24 = this.children;
            j = var24.length;

            for(int var26 = 0; var26 < j; ++var26) {
                EventExecutor e = var24[var26];
                e.terminationFuture().addListener(terminationListener);
            }

            Set<EventExecutor> childrenSet = new LinkedHashSet(this.children.length);
            Collections.addAll(childrenSet, this.children);
            this.readonlyChildren = Collections.unmodifiableSet(childrenSet);
        }
    }
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
    //直接调用了NioEventLoop的构造函数
        return new NioEventLoop(this, executor, (SelectorProvider)args[0], ((SelectStrategyFactory)args[1]).newSelectStrategy(), (RejectedExecutionHandler)args[2]);
    }
public final class NioEventLoop extends SingleThreadEventLoop {
	private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioEventLoop.class);
    private static final int CLEANUP_INTERVAL = 256;
    private static final boolean DISABLE_KEYSET_OPTIMIZATION = SystemPropertyUtil.getBoolean("io.netty.noKeySetOptimization", false);
    private static final int MIN_PREMATURE_SELECTOR_RETURNS = 3;
    private static final int SELECTOR_AUTO_REBUILD_THRESHOLD;
    private final IntSupplier selectNowSupplier = new IntSupplier() {
        public int get() throws Exception {
            return NioEventLoop.this.selectNow();
        }
    };
    private final Callable<Integer> pendingTasksCallable = new Callable<Integer>() {
        public Integer call() throws Exception {
            return NioEventLoop.super.pendingTasks();
        }
    };
 //事件选择器
    private Selector selector;
    private Selector unwrappedSelector;
    private SelectedSelectionKeySet selectedKeys;
    private final SelectorProvider provider;
    private final AtomicBoolean wakenUp = new AtomicBoolean();
    private final SelectStrategy selectStrategy;
    private volatile int ioRatio = 50;
    private int cancelledKeys;
    private boolean needsToSelectAgain;

    NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider, SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
        super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
        if (selectorProvider == null) {
            throw new NullPointerException("selectorProvider");
        } else if (strategy == null) {
            throw new NullPointerException("selectStrategy");
        } else {
            this.provider = selectorProvider;
         //这里调用了openSelector()方法生成SelectorTuple,而在openSelector()里面实际上是
         //调用了provider.openSelector()生成了selector赋值给了SelectorTuple
         //所以下面可以拿到selector,这个过程和原生的NIO编程是一样的过程
            NioEventLoop.SelectorTuple selectorTuple = this.openSelector();
            this.selector = selectorTuple.selector;
            this.unwrappedSelector = selectorTuple.unwrappedSelector;
            this.selectStrategy = strategy;
        }
    }

​ 我们之前有说过,每个EventLoop其实是一个只有一个线程的线程池(SingleThreadPool),内部维护着一个线程 Thread 和几个阻塞队列,那么是否可以证明呢?

​ 每个EventLoop包含的线程Thread定义在父类SingleThreadEventExecutor中,而每个EventLoop包含有两个队列,一个是SingleThreadEventExecutor中的taskQueue,主要负责保存各种任务,比如处理事件等,另一个是SingleThreadEventLoop中的tailTask,用于每次事件循环后置任务处理。

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

​ 这也就证明了前面说的结论是正确的。NioEventLoop作为 IO 事件处理的主要组件,必然离不开对事件的处理机制,在 NioEventLoop 的 run 方法,就有 selector 上进行 select 和调用 processSelectedKeys()处理各种事件集。

protected void run() {
        while(true) {
            while(true) {
                try {
                    switch(this.selectStrategy.calculateStrategy(this.selectNowSupplier, this.hasTasks())) {
                 //在接口SelectStrategy中,有两个成员变量。SELECT=-1和CONTINUE=-2
                    case -2:
                        continue;
                    case -1:
                        this.select(this.wakenUp.getAndSet(false));
                        if (this.wakenUp.get()) {
                            this.selector.wakeup();
                        }
                    default:
                        this.cancelledKeys = 0;
                        this.needsToSelectAgain = false;
                   //ioRatio是一个比例,表示线程处理io事件和处理队列中Task的时间比,缺省值1:1
                        int ioRatio = this.ioRatio;
                        if (ioRatio == 100) {
                            try {
                            //真正的循环选择器处理事件是在这个processSelectedKeys方法里
                                this.processSelectedKeys();
                            } finally {
                                this.runAllTasks();
                            }
                        } else {
                            long ioStartTime = System.nanoTime();
                            boolean var13 = false;

                            try {
                                var13 = true;
                                this.processSelectedKeys();
                                var13 = false;
                            } finally {
                                if (var13) {
                                    long ioTime = System.nanoTime() - ioStartTime;
                                    this.runAllTasks(ioTime * (long)(100 - ioRatio) / (long)ioRatio);
                                }
                            }

                            long ioTime = System.nanoTime() - ioStartTime;
                            this.runAllTasks(ioTime * (long)(100 - ioRatio) / (long)ioRatio);
                        }
                    }
                } catch (Throwable var21) {
                    handleLoopException(var21);
                }

                try {
                    if (this.isShuttingDown()) {
                        this.closeAll();
                        if (this.confirmShutdown()) {
                            return;
                        }
                    }
                } catch (Throwable var18) {
                    handleLoopException(var18);
                }
            }
        }
    }

​ 接下来看看processSelectedKeys这个方法:

private void processSelectedKeys() {
        if (this.selectedKeys != null) {
            this.processSelectedKeysOptimized();
        } else {
        //processSelectedKeysPlain参数是拿到所有事件的key集合,然后进入这个方法看看
            this.processSelectedKeysPlain(this.selector.selectedKeys());
        }
    }
private void processSelectedKeysPlain(Set<SelectionKey> selectedKeys) {
   //接下来的步骤其实跟我们原生的NIO编程步骤大致相似的
        if (!selectedKeys.isEmpty()) {
         //如果事件集合不为空,就遍历处理事件
            Iterator i = selectedKeys.iterator();
            while(true) {
                SelectionKey k = (SelectionKey)i.next();
             //拿到附着的Channel,在AbstractNioChannel中的doRegister方法讲解时,就有说过会把channel附着
             //下面会贴出附着的源码图
                Object a = k.attachment();
                i.remove();
                if (a instanceof AbstractNioChannel) {
                  //处理事件,进这个方法看看
                    this.processSelectedKey(k, (AbstractNioChannel)a);
                } else {
                    NioTask<SelectableChannel> task = (NioTask)a;
                    processSelectedKey(k, task);
                }
                if (!i.hasNext()) {
                    break;
                }
                if (this.needsToSelectAgain) {
                    this.selectAgain();
                    selectedKeys = this.selector.selectedKeys();
                    if (selectedKeys.isEmpty()) {
                        break;
                    }

                    i = selectedKeys.iterator();
                }
            }
        }
    }

在这里插入图片描述

private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
        final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
    //校验key的可用性
        if (!k.isValid()) {
            final EventLoop eventLoop;
            try {
                eventLoop = ch.eventLoop();
            } catch (Throwable ignored) {
                return;
            }
            if (eventLoop != this || eventLoop == null) {
                return;
            }
            unsafe.close(unsafe.voidPromise());
            return;
        }

        try {
            int readyOps = k.readyOps();
            // 连接connect事件
            if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
                int ops = k.interestOps();
                ops &= ~SelectionKey.OP_CONNECT;
                k.interestOps(ops);
                unsafe.finishConnect();
            }
            //写write事件
            if ((readyOps & SelectionKey.OP_WRITE) != 0) {
                ch.unsafe().forceFlush();
            }
            // 接受连接accept事件 或者 读read事件
            if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
                unsafe.read();
            }
        } catch (CancelledKeyException ignored) {
            unsafe.close(unsafe.voidPromise());
        }
    }

​ 至此,Netty基本的组件都讲完了,接下来将会从整个Netty的流程来讲前面所讲的组件串起来讲一遍,相信大家听完以后就不会想现在一样感觉学会了又感觉没学会。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值