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