【Netty4】netty对selectedKeys进行优化

1. 我们的问题

netty在创建selector的时候就尝试了优化,具体优化其实是将底层的数据结构从HashSet改为了数组,可以从SelectedSelectionKeySet和SelectorImpl的源码看到这一点,这里就不列了。

记住有个优化就行了,下面会用到这个知识

但是由此引发一个问题,当开启优化后,那么有效连接集合的数据是从哪来的?

当IO事件发生后,会紧接着调用processSelectedKeys()来处理具体的IO消息:

public final class NioEventLoop extends SingleThreadEventLoop {
    private void processSelectedKeys() {
        if (selectedKeys != null) {
             //开启优化
            processSelectedKeysOptimized();
        } else {
           //未开启优化
            processSelectedKeysPlain(selector.selectedKeys());
        }
    }

默认开启优化,走到该分支processSelectedKeysOptimized(),问题来了,该方法内部直接使用成员变量selectedKeys,那么这个集合的数据是怎么来的呢?我们没有调用类似else分支里面的selector.selectedKeys()

在这里插入图片描述

2. 问题分析

问题很简单,但是不太容易直接想到。

原因就是优化引起差别的,我们看下具体是怎么优化的:

private SelectorTuple openSelector() {
    final Selector unwrappedSelector;
    try {
        //[1] 根据底层的IO模型来创建一个selector,这里的selector就是java中NIO的selector
        unwrappedSelector = provider.openSelector();
    } catch (IOException e) {
        throw new ChannelException("failed to open a new selector", e);
    }
    // [2]如果未开启优化则直接就返回了,SelectorTuple可以视为一个持有selector引用的句柄
    if (DISABLE_KEY_SET_OPTIMIZATION) {
        return new SelectorTuple(unwrappedSelector);
    }
  //[3] 开启优化参数,则进行优化
    Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
        @Override
        public Object run() {
            try {
                // 通过反射创建一个selector的具体实例
                return Class.forName(
                        "sun.nio.ch.SelectorImpl",
                        false,
                        PlatformDependent.getSystemClassLoader());
            } catch (Throwable cause) {
                return cause;
            }
        }
    });

    final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;
    // [4]netty自己包装的一个selectKey的集合类,回被用来替换selector原生的selectedKeys成员变量
    final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();

    Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
        @Override
        public Object run() {
            try {//反射,获取selectedKeys字段,后面会替换这个私有的成员变量
                Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
                Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");

                if (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) {
                    // java 9 以上版本会用Unsafe类直接底层替换SelectionKeySet
                }
                // 利用反射将原生selector中的两个属性替换为netty自己的包装类
                selectedKeysField.set(unwrappedSelector, selectedKeySet);
                publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);
                return null;
            } catch (NoSuchFieldException e) {
                return e;
            } catch (IllegalAccessException e) {
                return e;
            }
        }
    });
    //[5] 当前NioEventLoop就持有这个自定义的集合
    selectedKeys = selectedKeySet;
    return new SelectorTuple(unwrappedSelector, new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
}
  • 【1】 根据底层的IO模型来创建一个selector,这里的selector就是java中NIO的selector
  • 【2】如果未开启优化则直接就返回了,SelectorTuple可以视为一个持有selector引用的句柄
  • 【3】 开启优化参数,则进行优化。默认是开启优化的。
  • 【4】netty自己包装的一个selectKey的集合类,回被用来替换selector原生的selectedKeys成员变量
  • 【5】当前NioEventLoop就持有这个自定义的集合。

优化的核心内容就是用自定义的集合替换有效key的集合,优点是效率高。

我们看下原生的语法:

在这里插入图片描述
原生的语法就是未开启优化processSelectedKeysPlain(selector.selectedKeys());分支入参中的语法,而当开启优化后,当前NioEventLoop就持有这个自定义的集合了。当IO事件发生后,就绪的channels和keys就会放入selector内,我们知道java中是对象引用,因此,我们直接用这个被自己持有的集合就行了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值