Netty源碼分析第二章: NioEventLoophtml
第五節: 優化selectorjava
在剖析selector輪詢以前, 咱們先講解一下selector的建立過程api
回顧以前的小節, 在建立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()中:ide
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; }
這裏代碼比較長, 咱們一點一點的剖析:oop
首先 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();
這裏一步建立了這個優化後的數據結構spa
簡單跟一下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所對應的數組中