Netty分布式NioEventLoop優(yōu)化selector源碼解析
優(yōu)化selector
selector的創(chuàng)建過(guò)程
在剖析selector輪詢之前, 我們先講解一下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è)類的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)類
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類型, 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è)類的構(gòu)造方法:
SelectedSelectionKeySet() {
keysA = new SelectionKey[1024];
keysB = keysA.clone();
}初始化了兩個(gè)屬性keysA和keysB, 說(shuō)明這類其實(shí)底層是通過(guò)數(shù)組實(shí)現(xiàn)的, 通過(guò)操作數(shù)組下標(biāo)會(huì)有更高的效率
這個(gè)類的的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)類, 如果不是, 則直接返回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)文章
org.apache.ibatis.annotations不存在的問(wèn)題
這篇文章主要介紹了org.apache.ibatis.annotations不存在的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
springboot統(tǒng)一異常處理(返回json)并格式化異常
這篇文章主要介紹了springboot統(tǒng)一異常處理(返回json)并格式化異常,對(duì)spring boot的默認(rèn)異常處理方式進(jìn)行修改,要統(tǒng)一返回?cái)?shù)據(jù)格式,優(yōu)雅的數(shù)據(jù)交互,優(yōu)雅的開發(fā)應(yīng)用,需要的朋友可以參考下2023-07-07
使用springboot 獲取控制器參數(shù)的幾種方法小結(jié)
這篇文章主要介紹了使用springboot 獲取控制器參數(shù)的幾種方法小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
手把手教你idea中創(chuàng)建一個(gè)javaweb(webapp)項(xiàng)目詳細(xì)圖文教程
這篇文章主要介紹了如何使用IntelliJ?IDEA創(chuàng)建一個(gè)Maven項(xiàng)目,并配置Tomcat服務(wù)器進(jìn)行運(yùn)行,過(guò)程包括創(chuàng)建項(xiàng)目、配置運(yùn)行環(huán)境、部署項(xiàng)目以及測(cè)試運(yùn)行,需要的朋友可以參考下2025-01-01
springboot2中session超時(shí),退到登錄頁(yè)面方式
這篇文章主要介紹了springboot2中session超時(shí),退到登錄頁(yè)面方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01

