Netty分布式NioEventLoop優(yōu)化selector源碼解析
優(yōu)化selector
selector的創(chuàng)建過程
在剖析selector輪詢之前, 我們先講解一下selector的創(chuàng)建過程
回顧之前的小節(jié), 在創(chuàng)建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 { //調(diào)用jdk底層的api selector = provider.openSelector(); } catch (IOException e) { throw new ChannelException("failed to open a new selector", e); } //判斷是否需要關(guān)閉優(yōu)化(默認(rèn)false, 也就是默認(rèn)需要優(yōu)化) if (DISABLE_KEYSET_OPTIMIZATION) { return selector; } //用這個數(shù)據(jù)結(jié)構(gòu)替換原生的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的實現(xiàn)類 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); } //如果不是他的實現(xiàn), 就直接返回原生select return selector; } //如果是它的實現(xiàn), 就拿到其class對象 final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass; Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { try { //通過反射拿到selectedKeys和publicSelectedKeys兩個屬性, 默認(rèn)這兩個屬性底層都是hashSet方式實現(xiàn)的 Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys"); Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys"); //設(shè)置成可修改的 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 { //將優(yōu)化后的keySet保存成NioEventLoop的成員變量 selectedKeys = selectedKeySet; logger.trace("instrumented a special java.util.Set into: {}", selector); } return selector; }
代碼剖析
這里代碼比較長, 我們一點一點的剖析:
首先 selector = provider.openSelector() 這里創(chuàng)建了jdk底層的selector
if (DISABLE_KEYSET_OPTIMIZATION) { return selector; }
這里判斷了是否關(guān)閉優(yōu)化功能, 默認(rèn)是false, 也就是需要優(yōu)化, 這里的意思就是netty需要對jdk原生的selector進(jìn)行了優(yōu)化, 我們知道selector在select()操作時候, 會通過selector.selectedKeys()操作返回一個Set<SelectionKey>, 這個是Set類型, netty對這個set進(jìn)行了處理, 使用SelectedSelectionKeySet的數(shù)據(jù)結(jié)構(gòu)進(jìn)行替換, 當(dāng)在select()操作時將key存入一個SelectedSelectionKeySet的數(shù)據(jù)結(jié)構(gòu)中
final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
這里一步創(chuàng)建了這個優(yōu)化后的數(shù)據(jù)結(jié)構(gòu)
簡單跟一下SelectedSelectctionKeySet這個類的構(gòu)造方法:
SelectedSelectionKeySet() { keysA = new SelectionKey[1024]; keysB = keysA.clone(); }
初始化了兩個屬性keysA和keysB, 說明這類其實底層是通過數(shù)組實現(xiàn)的, 通過操作數(shù)組下標(biāo)會有更高的效率
這個類的的flip()方法, 則返SelectionKey[]數(shù)組
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()) 創(chuàng)建了一個SelectorImpl的class對象
if(!(maybeSelectorImplClass instanceof Class) ||!((Class<?>) maybeSelectorImplClass).isAssignableFrom(selector.getClass()))
這里判斷拿到的對象是否為class對象并且是否為Selector的實現(xiàn)類, 如果不是, 則直接返回jdk的selector
如果是, 就繼續(xù)轉(zhuǎn)化成class對象
然后就做了真正的替換操作:
//通過反射拿到selectedKeys和publicSelectedKeys兩個屬性, 默認(rèn)這兩個屬性底層都是hashSet方式實現(xiàn)的 Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys"); Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys"); //設(shè)置成可修改的 selectedKeysField.setAccessible(true); publicSelectedKeysField.setAccessible(true); //將selector的這兩個屬性替換成Netty的selectedKeySet selectedKeysField.set(selector, selectedKeySet); publicSelectedKeysField.set(selector, selectedKeySet);
通過注釋我們不難看出, 這里將新創(chuàng)建selectedKeySet替換了selector對象中的selectedKeysField, 和selectedKeysField兩個屬性
最后通過 selectedKeys = selectedKeySet 將優(yōu)化的數(shù)據(jù)結(jié)構(gòu)selectedKeySet保存在NioEventLoop的成員變量中
最后返回優(yōu)化后的selector
這樣, selector在select()操作的過程中, 如果有就緒事件則會將返回的key存放在selectedKeySet所對應(yīng)的數(shù)組中
以上就是Netty分布式NioEventLoop優(yōu)化selector源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Netty分布式NioEventLoop優(yōu)化selector的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java?fastjson傳輸long數(shù)據(jù)卻接收到了int的問題
這篇文章主要介紹了java?fastjson傳輸long數(shù)據(jù)卻接收到了int的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01詳解Java數(shù)據(jù)結(jié)構(gòu)之平衡二叉樹
平衡二叉樹(Balanced?Binary?Tree)又被稱為AVL樹(有別于AVL算法),且具有以下性質(zhì):它是一?棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,并且左右兩個子樹都是一棵平衡二叉樹。本文將詳解介紹一下平衡二叉樹的原理與實現(xiàn),需要的可以參考一下2022-02-02Java開發(fā)之手把手教你搭建企業(yè)級工程SSM框架
這篇文章主要為大家介紹Java教程中搭建企業(yè)級工程SSM框架,手把手的過程操作,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-09-09關(guān)于mybatis callSettersOnNulls 配置解析
這篇文章主要介紹了關(guān)于mybatis callSettersOnNulls 配置,非常不錯,具有一定的參考借鑒價值 ,需要的朋友可以參考下2018-06-06springboot2啟動時執(zhí)行,初始化(或定時任務(wù))servletContext問題
這篇文章主要介紹了springboot2啟動時執(zhí)行,初始化(或定時任務(wù))servletContext問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-01-01