• Netty源码分析第2章(NioEventLoop)---->第5节: 优化selector


     

    Netty源码分析第二章: NioEventLoop

     

    第五节: 优化selector

     

    在剖析selector轮询之前, 我们先讲解一下selector的创建过程

    回顾之前的小节, 在创建NioEventLoop中初始化了唯一绑定的selector:

    NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider, 
                 SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
        super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
        //代码省略
        provider = selectorProvider;
        selector = openSelector();
        selectStrategy = strategy;
    }

    这里 selector = openSelector() 初始化了selector

    我们跟到openSelector()中:

    private Selector openSelector() {
        final Selector selector;
        try {
            //调用jdk底层的api
            selector = provider.openSelector();
        } catch (IOException e) {
            throw new ChannelException("failed to open a new selector", e);
        }
        //判断是否需要关闭优化(默认false, 也就是默认需要优化)
        if (DISABLE_KEYSET_OPTIMIZATION) {
            return selector;
        }
        //用这个数据结构替换原生的SelectionKeySet
        final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
        Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                try {
                    //通过反射拿到sun.nio.ch.SelectorImpl这个类的class对象
                    return Class.forName("sun.nio.ch.SelectorImpl", false, PlatformDependent.getSystemClassLoader());
                } catch (ClassNotFoundException e) {
                    return e;
                } catch (SecurityException e) {
                    return e;
                }
            }
        });
        //判断拿到的是不是class对象并且是不是Selector的实现类
        if (!(maybeSelectorImplClass instanceof Class) ||!((Class<?>) maybeSelectorImplClass).isAssignableFrom(selector.getClass())) {
            if (maybeSelectorImplClass instanceof Exception) {
                Exception e = (Exception) maybeSelectorImplClass;
                logger.trace("failed to instrument a special java.util.Set into: {}", selector, e);
            }
            //如果不是他的实现, 就直接返回原生select
            return selector;
        }
        //如果是它的实现, 就拿到其class对象
        final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;
        Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                try {
                    //通过反射拿到selectedKeys和publicSelectedKeys两个属性, 默认这两个属性底层都是hashSet方式实现的
                    Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
                    Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
                    //设置成可修改的
                    selectedKeysField.setAccessible(true);
                    publicSelectedKeysField.setAccessible(true);
                    //将selector的这两个属性替换成Netty的selectedKeySet
                    selectedKeysField.set(selector, selectedKeySet);
                    publicSelectedKeysField.set(selector, selectedKeySet);
                    return null;
                } catch (NoSuchFieldException e) {
                    return e;
                } catch (IllegalAccessException e) {
                    return e;
                } catch (RuntimeException e) {
                    if ("java.lang.reflect.InaccessibleObjectException".equals(e.getClass().getName())) {
                        return e;
                    } else {
                        throw e;
                    }
                }
            }
        });
        if (maybeException instanceof Exception) {
            selectedKeys = null;
            Exception e = (Exception) maybeException;
            logger.trace("failed to instrument a special java.util.Set into: {}", selector, e);
        } else {
            //将优化后的keySet保存成NioEventLoop的成员变量
            selectedKeys = selectedKeySet;
            logger.trace("instrumented a special java.util.Set into: {}", selector);
        }
        return selector;
    }

    这里代码比较长, 我们一点一点的剖析:

    首先 selector = provider.openSelector() 这里创建了jdk底层的selector

    if (DISABLE_KEYSET_OPTIMIZATION) {
        return selector;
    }

    这里判断了是否关闭优化功能, 默认是false, 也就是需要优化, 这里的意思就是netty需要对jdk原生的selector进行了优化, 我们知道selector在select()操作时候, 会通过selector.selectedKeys()操作返回一个Set<SelectionKey>, 这个是Set类型, netty对这个set进行了处理, 使用SelectedSelectionKeySet的数据结构进行替换, 当在select()操作时将key存入一个SelectedSelectionKeySet的数据结构中

     

    final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();

    这里一步创建了这个优化后的数据结构

    简单跟一下SelectedSelectctionKeySet这个类的构造方法:

    SelectedSelectionKeySet() {
        keysA = new SelectionKey[1024];
        keysB = keysA.clone();
    }

    初始化了两个属性keysA和keysB, 说明这类其实底层是通过数组实现的, 通过操作数组下标会有更高的效率

    这个类的的flip()方法, 则返SelectionKey[]数组

    SelectionKey[] flip() {
        if (isA) {
            isA = false;
            keysA[keysASize] = null;
            keysBSize = 0;
            return keysA;
        } else {
            isA = true;
            keysB[keysBSize] = null;
            keysASize = 0;
            return keysB;
        }
    }

    再看下其他方法:

    @Override
    public boolean remove(Object o) {
        return false;
    }
    
    @Override
    public boolean contains(Object o) {
        return false;
    }
    @Override
    public Iterator<SelectionKey> iterator() {
        throw new UnsupportedOperationException();
    }

    我们看到remove()方法, contains()方法都返回了false, 说明其不支持删除方法和包含方法, iterator()方法则直接抛出异常, 说明其不支持迭代器操作

    回到openSelector()中:

    再往下看, 这里通过 Class.forName("sun.nio.ch.SelectorImpl", false, PlatformDependent.getSystemClassLoader()) 创建了一个SelectorImpl的class对象

     if(!(maybeSelectorImplClass instanceof Class) ||!((Class<?>) maybeSelectorImplClass).isAssignableFrom(selector.getClass())) 

    这里判断拿到的对象是否为class对象并且是否为Selector的实现类, 如果不是, 则直接返回jdk的selector

    如果是, 就继续转化成class对象

    然后就做了真正的替换操作:

    //通过反射拿到selectedKeys和publicSelectedKeys两个属性, 默认这两个属性底层都是hashSet方式实现的
    Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
    Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
    //设置成可修改的
    selectedKeysField.setAccessible(true);
    publicSelectedKeysField.setAccessible(true);
    //将selector的这两个属性替换成Netty的selectedKeySet
    selectedKeysField.set(selector, selectedKeySet);
    publicSelectedKeysField.set(selector, selectedKeySet);

    通过注释我们不难看出, 这里将新创建selectedKeySet替换了selector对象中的selectedKeysField, 和selectedKeysField两个属性

    最后通过 selectedKeys = selectedKeySet 将优化的数据结构selectedKeySet保存在NioEventLoop的成员变量中

    最后返回优化后的selector

    这样, selector在select()操作的过程中, 如果有就绪事件则会将返回的key存放在selectedKeySet所对应的数组中

     

    上一节: NioEventLoop线程启动

    下一节: 执行select操作

     

  • 相关阅读:
    Ehcache(04)——设置缓存的大小
    Ehcache(03)——Ehcache中储存缓存的方式
    Ehcache(02)——ehcache.xml简介
    Ehcache(01)——简介、基本操作
    linux 下开机自动启动tomcat服务
    Git_常用链接
    Android_listview点击失效
    Android_Drawable Bitmap Canvas Paint之间区别[转]
    Android_广播
    Notification(Notification的通知栏常驻、Notification的各种样式、Notification点击无效)
  • 原文地址:https://www.cnblogs.com/xiangnan6122/p/10203116.html
Copyright © 2020-2023  润新知