netty源码阅读之EventLoopGroup实例化过程

本文详细分析了Netty中EventLoopGroup的构造过程,包括NioEventLoopGroup的创建、EventLoop的初始化、线程工厂DefaultThreadFactory的作用以及如何为每个EventLoop注册监听器。通过源码跟踪,揭示了Netty在多线程和事件分发方面的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

《netty in action》的书也翻了几遍,大佬们的源码分析博客也看了一点。然后看书是真的没有学会,所以是真需要去实践学习~。

EventLoopGroup族类

EventLoopGroup这不能单个看某个类,netty里面有许多类都得拎起整个族谱看。大师们在继承上的代码组织的很厉害,废话不多说debug走起。

在这里插入图片描述

EventLoopGroup构造器

然后跟着代码执行流程走,最后关于NioEventLoopGroup调到这里

 public NioEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory,
                             final SelectorProvider selectorProvider,
                             final SelectStrategyFactory selectStrategyFactory) {
        super(nThreads, executor, chooserFactory, selectorProvider, selectStrategyFactory,
                RejectedExecutionHandlers.reject());
    }

EventLoop构造器

继续追进它的父类MultithreadEventLoopGroup构造器,其实就是确定当前这个EventLoopGroup该分配多少个EventLoop。

  /**
     * @see {@link MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor, Object...)}
     */
    protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
    }

MultithreadEventExecutorGroup构造器

继续跟进去然后到达MultithreadEventExecutorGroup这个类,这个类下的如下代码所示的才是这个真正逻辑。

/**
     * Create a new instance.
     *
     * @param nThreads          the number of threads that will be used by this instance.
     * @param executor          the Executor to use, or {@code null} if the default should be used.
     * @param chooserFactory    the {@link EventExecutorChooserFactory} to use.
     * @param args              arguments which will passed to each {@link #newChild(Executor, Object...)} call
     */
    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) {
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }

        children = new EventExecutor[nThreads];

        for (int i = 0; i < nThreads; i ++) {
            boolean success = false;
            try {
                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 {
                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);
    }

上面的代码就做了几件事情:
1. 创建一个executor对象。
2.根据nThreads给当前EventLoopGroup对象创建相应量的EventLoop对象
3.给EventLoopGroup对象创建一个chooser对象,用于将channel分派分配到对应的EventLoop干活。
4.给每一个EventLoop注册一个监听器
5.将eventloop的引用保留一份在 readonlyChildren集合下,供通过迭代器获取对应的eventloop。

下面开始阅读这5个步骤具体干了啥,起到啥作用。

创建executor对象

if (executor == null) {
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }

executor引用指向的对象是ThreadPerTaskExecutor,我们看一下该类的干了啥事

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) {
        threadFactory.newThread(command).start();
    }
}

DefaultThreadFactory

原来是委托了ThreadFactory帮干活,进去再看一下,DefaultThreadFactory就是给后面新拉起的线程取个名字,然后最核心的方法是newThread()用来创建线程,供后面用于线程。

/**
 * A {@link ThreadFactory} implementation with a simple naming rule.
 */
public class DefaultThreadFactory implements ThreadFactory {

    public DefaultThreadFactory(String poolName, boolean daemon, int priority, ThreadGroup threadGroup) {
        if (poolName == null) {
            throw new NullPointerException("poolName");
        }
        if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
            throw new IllegalArgumentException(
                    "priority: " + priority + " (expected: Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY)");
        }

        prefix = poolName + '-' + poolId.incrementAndGet() + '-';
        this.daemon = daemon;
        this.priority = priority;
        this.threadGroup = threadGroup;
    }

    public DefaultThreadFactory(String poolName, boolean daemon, int priority) {
        this(poolName, daemon, priority, System.getSecurityManager() == null ?
                Thread.currentThread().getThreadGroup() : System.getSecurityManager().getThreadGroup());
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread t = newThread(new DefaultRunnableDecorator(r), prefix + nextId.incrementAndGet());
        try {
            if (t.isDaemon()) {
                if (!daemon) {
                    t.setDaemon(false);
                }
            } else {
                if (daemon) {
                    t.setDaemon(true);
                }
            }

            if (t.getPriority() != priority) {
                t.setPriority(priority);
            }
        } catch (Exception ignored) {
            // Doesn't matter even if failed to set.
        }
        return t;
    }

    protected Thread newThread(Runnable r, String name) {
        return new FastThreadLocalThread(threadGroup, r, name);
    }

    private static final class DefaultRunnableDecorator implements Runnable {

        private final Runnable r;

        DefaultRunnableDecorator(Runnable r) {
            this.r = r;
        }

        @Override
        public void run() {
            try {
                r.run();
            } finally {
                FastThreadLocal.removeAll();
            }
        }
    }
}

接下来粗看一下哪里被调用到这个方法,挺好奇的
在这里插入图片描述
数目不多能通过名字猜出作用。FastThreadLocalThread就是netty内部对Thread进行包装的一个类,主要多放了一个threadLocalMap;类进行保存数据,供FastThreadLocal对象进行操作数据。

创建属于该EventLoopGroup的 EventExecutor

后面看NioEventLoop的逻辑。现在不追。

children = new EventExecutor[nThreads];
children[i] = newChild(executor, args)

由于该new方法是子类EventLoopGroup实现的所以需要跳回去。

@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]);
    }

创建属于该EventLoopGroup的 线程选择器

简单,后面用到再看执行流程

 chooser = chooserFactory.newChooser(children);

给每个Executor注册一个监听器

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

不知道有啥用,跟进去看一下它干啥的 private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);从注释看,出现最多的两个英文是Notify与listeners,所以是用来通知状态,现在不知道,先记下这个类SingleThreadEventExecutor,后面应该能看到结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值