1. 程式人生 > >Netty原始碼分析第2章(NioEventLoop)---->第5節: 優化selector

Netty原始碼分析第2章(NioEventLoop)---->第5節: 優化selector

 

第二章: 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();

這裡一步建立了這個優化後的資料結構, 簡單跟一下這個類的構造方法:

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()方法則直接丟擲異常, 說明其不支援迭代器操作

再往下看, 這裡通過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所對應的陣列中