成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

NioEventLoop源碼解析

開發(fā) 前端
NioEventLoopGroup在初始化過程中會構(gòu)建一個執(zhí)行器數(shù)組,數(shù)組內(nèi)部存儲的元素是NioEventLoop類型的,但是NioEventLoop是什么呢?為什么說他是Netty的精髓呢?

[[409020]]

本文轉(zhuǎn)載自微信公眾號「源碼學(xué)徒」,作者皇甫嗷嗷叫 。轉(zhuǎn)載本文請聯(lián)系源碼學(xué)徒公眾號。

 源碼分析

上一節(jié)課,我們就 new NioEventLoopGroup();的初始化過程做了一個深度的解析,后來我們發(fā)現(xiàn),NioEventLoopGroup在初始化過程中會構(gòu)建一個執(zhí)行器數(shù)組,數(shù)組內(nèi)部存儲的元素是NioEventLoop類型的,但是NioEventLoop是什么呢?為什么說他是Netty的精髓呢?

我們直接進(jìn)入到NioEventLoop看他的構(gòu)造方法:

上一節(jié)課我們是在循環(huán)填充執(zhí)行器數(shù)組的過程中創(chuàng)建的,具體參見上一節(jié)課的for循環(huán)中的 newChild方法,這里直接分析源碼

  1. NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider, 
  2.              SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler, 
  3.              EventLoopTaskQueueFactory queueFactory) { 
  4.     //保存外部線程任務(wù)newTaskQueue(queueFactory) 
  5.     super(parent, executor, false, newTaskQueue(queueFactory), newTaskQueue(queueFactory), 
  6.           rejectedExecutionHandler); 
  7.     this.provider = ObjectUtil.checkNotNull(selectorProvider, "selectorProvider"); 
  8.     this.selectStrategy = ObjectUtil.checkNotNull(strategy, "selectStrategy"); 
  9.     final SelectorTuple selectorTuple = openSelector(); 
  10.     this.selector = selectorTuple.selector; 
  11.     this.unwrappedSelector = selectorTuple.unwrappedSelector; 

關(guān)于super我們一會再往后追

一、保存選擇器生產(chǎn)者

  1. this.provider = ObjectUtil.checkNotNull(selectorProvider, "selectorProvider"); 

是綁定了一個類似于生產(chǎn)者的東西,使我們再初始化NioEventLoopGroup的時候初始化的,使用該生產(chǎn)者,后續(xù)可以獲取選擇器或者Socket通道等!

二、保存選擇器

  1. this.selectStrategy = ObjectUtil.checkNotNull(strategy, "selectStrategy"); 

保存一個默認(rèn)的選擇策略到NioEventLoop對象里面

三、開啟一個選擇器

  1. final SelectorTuple selectorTuple = openSelector(); 

開啟一個選擇器包裝對象,內(nèi)含一個選擇器!Netty官方為了Netty性能的進(jìn)一步優(yōu)化,喪心病狂的對這個選擇器也進(jìn)行了優(yōu)化,我們跟進(jìn)一下openSelector方法,看看他是如何優(yōu)化的,內(nèi)部代碼比較復(fù)雜,我們逐行分析:

1. 獲取原始的選擇器

  1. unwrappedSelector = provider.openSelector(); 

使用原始的生產(chǎn)者對象,獲取一個原始的選擇器,后續(xù)使用!

2. 判斷是否啟動用選擇器優(yōu)化

  1. //禁用優(yōu)化選項(xiàng)  默認(rèn)false 
  2. if (DISABLE_KEY_SET_OPTIMIZATION) { 
  3.     //如果不優(yōu)化那么就直接包裝原始的選擇器 
  4.     return new SelectorTuple(unwrappedSelector); 

DISABLE_KEY_SET_OPTIMIZATION默認(rèn)為false, 當(dāng)禁用優(yōu)化的時候,會將selector選擇器直接進(jìn)行包裝返回! 默認(rèn)會進(jìn)行優(yōu)化,所以一般不會進(jìn)這個邏輯分支!

3. 獲取一個選擇器的類的對象

  1. //如果需要優(yōu)化  
  2. //反射獲取對應(yīng)的類的對象 SelectorImpl 
  3. Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() { 
  4.     @Override 
  5.     public Object run() { 
  6.         try { 
  7.             return Class.forName( 
  8.                 "sun.nio.ch.SelectorImpl"
  9.                 false
  10.                 PlatformDependent.getSystemClassLoader()); 
  11.         } catch (Throwable cause) { 
  12.             return cause; 
  13.         } 
  14.     } 
  15. }); 

這個代碼是返回一個 SelectorImpl的Class對象,這里是返回SelectorImpl的Class對象!我們由上述代碼可以看出來,如果獲取失敗,會返回一個異常,異常的話肯定不行,所以就要對可能會發(fā)生的異常做出操作:

  1. //如果沒有獲取成功 
  2. f (!(maybeSelectorImplClass instanceof Class) || 
  3.    // 確保當(dāng)前的選擇器實(shí)現(xiàn)是我們可以檢測到的。  判斷是 unwrappedSelector的子類或者同類 
  4.    !((Class<?>) maybeSelectorImplClass).isAssignableFrom(unwrappedSelector.getClass())) { 
  5.    //發(fā)生異常 
  6.    if (maybeSelectorImplClass instanceof Throwable) { 
  7.        Throwable t = (Throwable) maybeSelectorImplClass; 
  8.        logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, t); 
  9.    } 
  10.    //還是包裝為未優(yōu)化的選擇器 
  11.    return new SelectorTuple(unwrappedSelector); 

如果發(fā)生了異常,或者獲取的和原始選擇器不是一個對象,就還使用原始選擇器包裝返回!

4. 創(chuàng)建一個優(yōu)化后的selectKeys

  1. final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet(); 

使用過NIO的都應(yīng)該知道,使用選擇器是能夠獲取一個事件的Set集合的,這里Netty官方自己實(shí)現(xiàn)了一個Set集合,內(nèi)部使用數(shù)組來進(jìn)行優(yōu)化!因?yàn)镠ashset集合是使用HashMap方法來實(shí)現(xiàn)的,(this ->Object)  再添加元素的時候如果發(fā)生了hash碰撞的話會遍歷hash槽上的鏈表  算法復(fù)雜度為O(n),但是數(shù)組不一樣  數(shù)組是O(1)  所以Netty官方使用數(shù)組來優(yōu)化選擇器事件集合  默認(rèn)是1024  滿了之后2倍擴(kuò)容!

大家可以簡單的把它看做一個Set集合,只不過他是使用數(shù)組的形式來實(shí)現(xiàn)的!內(nèi)部重寫了add、size、iterator的方法,其余方法全部廢棄!

這個是Netty對選擇器優(yōu)化的一個重要對象,使得再追加事件的時候,算法復(fù)雜度由O(N)直接變?yōu)榱薕(1)!

5. 開始進(jìn)行反射替換selectedKeys

  1. //開始進(jìn)行反射替換 
  2. Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() { 
  3.     @Override 
  4.     public Object run() { 
  5.         try { 
  6.             //獲取選擇器事件中的 事件對象 selectedKeys的屬性對象 
  7.             Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys"); 
  8.             //獲取公開選擇的密鑰 
  9.             Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys"); 
  10.  
  11.             //java9且存在 Unsafe的情況下 直接替換內(nèi)存空間的數(shù)據(jù) 
  12.             if (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) { 
  13.                 // 讓我們嘗試使用sun.misc.Unsafe替換SelectionKeySet。 
  14.                 // 這使我們也可以在Java9 +中執(zhí)行此操作,而無需任何額外的標(biāo)志。 
  15.                 long selectedKeysFieldOffset = PlatformDependent.objectFieldOffset(selectedKeysField); 
  16.                 long publicSelectedKeysFieldOffset = 
  17.                     PlatformDependent.objectFieldOffset(publicSelectedKeysField); 
  18.  
  19.                 if (selectedKeysFieldOffset != -1 && publicSelectedKeysFieldOffset != -1) { 
  20.                     PlatformDependent.putObject( 
  21.                         unwrappedSelector, selectedKeysFieldOffset, selectedKeySet); 
  22.                     PlatformDependent.putObject( 
  23.                         unwrappedSelector, publicSelectedKeysFieldOffset, selectedKeySet); 
  24.                     return null
  25.                 } 
  26.                 // 如果沒法直接替換內(nèi)存空間的數(shù)據(jù) 就想辦法用反射 
  27.             } 
  28.             //java8或者java9+上述未操作完成的 使用反射來替換 
  29.             Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField, true); 
  30.             if (cause != null) { 
  31.                 return cause; 
  32.             } 
  33.             cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField, true); 
  34.             if (cause != null) { 
  35.                 return cause; 
  36.             } 
  37.             //開始進(jìn)行替換  將我們創(chuàng)建的優(yōu)化后的事件數(shù)組來反射的替換進(jìn)選擇器中 
  38.             selectedKeysField.set(unwrappedSelector, selectedKeySet); 
  39.             publicSelectedKeysField.set(unwrappedSelector, selectedKeySet); 
  40.             return null
  41.         } catch (NoSuchFieldException e) { 
  42.             return e; 
  43.         } catch (IllegalAccessException e) { 
  44.             return e; 
  45.         } 
  46.     } 
  47. }); 

代碼雖然多,但是,邏輯比較簡單!

  1. 首先獲取SelectorImpl類對象的 selectedKeys屬性和publicSelectedKeys屬性!
  2. 判斷使用的JDK版本是不是9以上,如果使用的9的話,直接操作JAVA的Unsafe對象操作系統(tǒng)的內(nèi)存空間!有關(guān)Unsafe的介紹,再零拷貝章節(jié)介紹的很詳細(xì),可以復(fù)習(xí)零拷貝章節(jié)! 我們這里使用的JDK8
  3. 如果使用的是JDK8,使用反射,將我們創(chuàng)建出來的SelectedKeys的優(yōu)化對象SelectedSelectionKeySet反射的替換進(jìn)unwrappedSelector這個原始的選擇器!

6. 包裝選擇器

  1. return new SelectorTuple(unwrappedSelector, new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet)); 

首先把unwrappedSelector選擇器包裝為 SelectedSelectionKeySetSelector包裝類!

再把unwrappedSelector和SelectedSelectionKeySetSelector對應(yīng)起來,包裝Wie元組返回!

四、保存優(yōu)化后的選擇器和原始選擇器

  1. this.selector = selectorTuple.selector; 
  2. this.unwrappedSelector = selectorTuple.unwrappedSelector; 

五、調(diào)用父類,創(chuàng)建隊(duì)列

  1. super(parent, executor, false, newTaskQueue(queueFactory),  
  2.       newTaskQueue(queueFactory),rejectedExecutionHandler); 

首先,他會通過newTaskQueue構(gòu)建兩個隊(duì)列 ,這兩個隊(duì)列是什么類型的呢?

上一節(jié)課我們分析過,queueFactory == null,所以會走如圖分支代碼,DEFAULT_MAX_PENDING_TASKS如果沒有指定的話,默認(rèn)是Integer.MAX,最小為16!我們進(jìn)入到 該分支代碼看一下,他創(chuàng)建的是一個什么隊(duì)列:

  1. public static <T> Queue<T> newMpscQueue() { 
  2.     return Mpsc.newMpscQueue(); 

可以看出他創(chuàng)建的是一個Mpsc隊(duì)列,他是一個多生產(chǎn)者,單消費(fèi)者隊(duì)列,是由jctools框架提供的,后續(xù)如果可以,我會具體對該隊(duì)列進(jìn)行一個講解,我們到這里就知道,再創(chuàng)建NIOEventLoop的時候,向父類內(nèi)部傳遞了兩個Mpsc隊(duì)列,我們繼續(xù)回到主線:

進(jìn)入到super(xxx)的源碼中:

  1. protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor, boolean addTaskWakesUp, Queue<Runnable> taskQueue, Queue<Runnable> tailTaskQueue, 
  2.                                     RejectedExecutionHandler rejectedExecutionHandler) { 
  3.     super(parent, executor, addTaskWakesUp, taskQueue, rejectedExecutionHandler); 
  4.     //保存一個 tailTasks  尾部隊(duì)列 
  5.     tailTasks = ObjectUtil.checkNotNull(tailTaskQueue, "tailTaskQueue"); 

這里會保存一個隊(duì)列,尾部隊(duì)列,這個尾部隊(duì)列,官方的意思是想對Netty 的運(yùn)行狀態(tài)做一些統(tǒng)計(jì)數(shù)據(jù),例如任務(wù)循環(huán)的耗時、占用物理內(nèi)存的大小等等,但是實(shí)際上應(yīng)用tailTasks的場景極少,這里不做太多講解!

我們繼續(xù)跟進(jìn)到super方法源碼里面:

  1. //parent   線程執(zhí)行器   false   mpsc隊(duì)列    拒絕策略 
  2. protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor, 
  3.                                         boolean addTaskWakesUp, Queue<Runnable> taskQueue, 
  4.                                           RejectedExecutionHandler rejectedHandler) { 
  5.     super(parent); 
  6.     this.addTaskWakesUp = addTaskWakesUp; 
  7.     this.maxPendingTasks = DEFAULT_MAX_PENDING_EXECUTOR_TASKS; 
  8.     //保存線程執(zhí)行器 
  9.     this.executor = ThreadExecutorMap.apply(executor, this); 
  10.     //創(chuàng)建一個隊(duì)列 Mpscq,外部線程執(zhí)行的時候使用這個隊(duì)列(不是在EventLoop的線程內(nèi)執(zhí)行的時候)  newTaskQueue(queueFactory) 
  11.     this.taskQueue = ObjectUtil.checkNotNull(taskQueue, "taskQueue"); 
  12.     //保存拒絕策略 
  13.     this.rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler"); 

這里是進(jìn)一步保存,將該NioEventLoop對應(yīng)的線程執(zhí)行器  、MpscQuerey任務(wù)隊(duì)列、對應(yīng)的拒絕策略保存起來!  大家再后續(xù)看到使用對應(yīng)變量的代碼千萬不要覺得陌生哦!

總結(jié)

創(chuàng)建和保存了兩個多生產(chǎn)者單消費(fèi)者隊(duì)列tailTasks和taskQueue

保存一個線程執(zhí)行器executor

保存一個拒絕策略,該拒絕策略主要用于隊(duì)列滿了之后如何處理!

保存一個選擇器生產(chǎn)者!

創(chuàng)建一個優(yōu)化后的選擇器,并進(jìn)行保存!

將原始選擇器和優(yōu)化后的選擇器進(jìn)行保存!

 

責(zé)任編輯:武曉燕 來源: 源碼學(xué)徒
相關(guān)推薦

2015-09-16 09:10:27

Java源碼解析

2022-05-20 10:32:49

事件循環(huán)器事件隊(duì)列鴻蒙

2020-12-01 15:00:20

Java 基礎(chǔ)

2021-02-20 06:09:46

libtask協(xié)程鎖機(jī)制

2012-11-06 11:07:59

jQueryJSjQuery框架

2024-11-18 16:15:00

2021-07-09 06:48:30

注冊源碼解析

2024-01-18 08:31:22

go實(shí)現(xiàn)gorm框架

2016-12-15 09:44:31

框架Caffe源碼

2010-01-25 10:35:12

Android復(fù)選框

2013-03-05 09:16:33

MySQLInnodb

2022-04-09 15:26:46

Kubernetes刪除操作源碼解析

2021-03-24 07:16:57

RocketMQ源碼解析Topic

2022-02-14 14:47:11

SystemUIOpenHarmon鴻蒙

2021-10-27 16:52:37

LayoutInfl源碼解析

2022-12-07 08:02:43

Spring流程IOC

2022-12-16 08:31:37

調(diào)度線程池源碼

2025-02-06 08:24:25

AQS開發(fā)Java

2021-10-20 07:18:50

開源輕量級緩存

2018-07-19 15:57:46

ViewStub源碼方法
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 成人av在线播放 | 久久久.com| 国产精品波多野结衣 | 欧洲色综合 | 久久久久久综合 | 久久国产亚洲 | 国产精品久久777777 | 亚洲欧美日韩中文字幕一区二区三区 | 狠狠干av | 99免费在线视频 | 国产成人99久久亚洲综合精品 | 免费黄网站在线观看 | 91精品久久久久久久 | 久久久久国产一区二区三区 | av中文字幕在线观看 | 精品国产一区二区三区日日嗨 | 中文字幕第一页在线 | 羞羞的视频在线看 | 日韩欧美专区 | 一本综合久久 | 国产伦精品一区二区三区四区视频 | 亚洲一区电影 | 91亚洲国产 | 黄色一级片视频 | 一级一级一级毛片 | 一级黄色裸片 | 超碰在线97国产 | 国产精品夜色一区二区三区 | 日韩国产在线 | 中文字幕一区二区三区精彩视频 | 国产日韩精品在线 | 99热视| 成人av电影网 | 久久精品国产一区二区三区不卡 | 日本aa毛片a级毛片免费观看 | 少妇淫片aaaaa毛片叫床爽 | 国产一级片网站 | 91av久久久| 中文字幕影院 | 欧美日韩三级在线观看 | 伊人成人免费视频 |