netty源码解析---bossGroup初始化

概述

本文主要讲述netty bossGroup初始化相关流程

初始化

bossGroup实际类型是,NioEventLoopGroup,即然探究初始化流程,那么直接进入构造方法

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

在进行NioEventLoopGroup进行构造的时候,会不断的调用重载构造,最终调用的构造如上
nThreads:线程数
executor:这里传来的是null
selectorProvider:这个对象可以用来获取selector
selectStrategyFactory:选择策略,对应selector的选择策略
RejectedExecutionHandlers.reject():拒绝策略
继续深挖

 static {
        DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
                "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
    }
    protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
    }

然后就会调用其父类的构造方法,这里获取电脑的cpu数,如果开发人员没有传入nThread,那么默认线程数就是cpu*2

接着还会调用其父类构造,我们来直接看调用的尽头

protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
      ...

        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) {
                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) {
                            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);
    }

在上面所看到的构造器才真正的进行初始化操作
首先是给executor进行初始化 newDefaultThreadFactory() ,在这个类里面我们可以看到一个newThread 的方法,返回出来的是一个Thread对象,由此可见,newDafaultThreadFactory 主要是用来返回一个线程的,至于ThreadPerTaskExecutor这个类,无非是对线程工厂进行了一层包装,然后继承了Executor这个类,并重写了execute,说明,这个类是专门用来启动线程的

然后根据 nThread 来创建对应大小的数组
接着循环这个数组,调用newChild 为其赋值

    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(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");
        }
        if (strategy == null) {
            throw new NullPointerException("selectStrategy");
        }

        provider = selectorProvider;
        final SelectorTuple selectorTuple = openSelector();
  
        selector = selectorTuple.selector;

        unwrappedSelector = selectorTuple.unwrappedSelector;

        selectStrategy = strategy;
    }

跟进到NioEventLoop 的构造 ,里面又调用了其父类的构造,我简单解释一下在这个父类构造里面做了那些事情
参数介绍:
parent:NioEventLoopGroup
executor:前面初始化过的线程池
false:先理解为就是一个标志位
DEFAULT_MAX_PENDING_TASKS:线程池的队列大小,可以通过系统参数设置
rejectedExecutionHandler:拒绝策略
简单的来说就是继续对线程池进行初始化,保存一下这个线程执行器,创建一个任务队列
接下来看一个比较重要的方法openSelector()
这个方法返回的是一个SelectorTuple对象 ,在这里面有两个selector对象

删除了一些不重要的代码
 private SelectorTuple openSelector() {
        final Selector unwrappedSelector;
      
         unwrappedSelector = provider.openSelector();
        Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                    return Class.forName(
                            "sun.nio.ch.SelectorImpl",
                            false,
                            PlatformDependent.getSystemClassLoader());
            }
        });

        final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;
        //netty自定义的Set
        final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();

        Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                try {
                    Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
                    Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");

                    if (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) {
                        // Let us try to use sun.misc.Unsafe to replace the SelectionKeySet.
                        // This allows us to also do this in Java9+ without any extra flags.
                        long selectedKeysFieldOffset = PlatformDependent.objectFieldOffset(selectedKeysField);
                        long publicSelectedKeysFieldOffset =
                                PlatformDependent.objectFieldOffset(publicSelectedKeysField);

                        if (selectedKeysFieldOffset != -1 && publicSelectedKeysFieldOffset != -1) {
                            PlatformDependent.putObject(
                                    unwrappedSelector, selectedKeysFieldOffset, selectedKeySet);
                            PlatformDependent.putObject(
                                    unwrappedSelector, publicSelectedKeysFieldOffset, selectedKeySet);
                            return null;
                        }
                    }
                    selectedKeysField.set(unwrappedSelector, selectedKeySet);
                    publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);
                    return null;
                } catch (NoSuchFieldException e) {
                    return e;
                } catch (IllegalAccessException e) {
                    return e;
                }
            }
        });
        selectedKeys = selectedKeySet;
        return new SelectorTuple(unwrappedSelector,
                                 new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
    }

这里首先调用了NIO的方法获取到了一个selector,随后获取SelectorImpl的class对象
在这个方法里面我们还能看到SelectedSelectionKeySet ,这是netty自定义的一个set集合,而netty获取SelectorImpl对象的目的,就是为了对这个返回的selector的属性进行替换,使用自定义的set使netty的性能进一步提升,随后就将替换后的selector和没有替换的selector(但是经过一层包装的selector)都封装在SelectorTuple这个对象返回

现在从这里回到MultithreadEventExecutorGroup里面,也就是说每一个NioEventLoop都保存着一个executor和一个Selector
接着就会将children传入newChooser这个方法,返回一个选择策略,这个选择策略就是用来选择NioEventLoop的策略

至此,NioEventLoopGroup的主要初始化流程完毕,主要就是创建了一个EventExecutor的数组,以及对线程池进行一些初始化的操作,替换selector的数据结构

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值