1,handler 機(jī)制中甥啄,存在哪些角色?各自承擔(dān)了什么功能融虽?
1.Handler :消息輔助類& 對(duì)外的接口& 向MQ投遞消息&消息的目標(biāo)處理者
2.Message :消息的載體&被Handler投遞&自帶Handler處理&自帶處理池
3.Looper :循環(huán)器&持有MQ&循環(huán)從MQ中獲取消息&TLS線程唯一
4.MessageQueue:基于時(shí)間的優(yōu)先級(jí)隊(duì)列&鏈表結(jié)構(gòu)&java與C++層的紐帶
[圖片上傳失敗...(image-25c28e-1616424380917)]
2.Handler機(jī)制中,Message和Runnable的區(qū)別彼绷?
1.本質(zhì)上沒有區(qū)別的萤衰,MQ只接受Message倦卖,Runnable 會(huì)被轉(zhuǎn)換成Message入隊(duì)
2.Runnable 通過getPostMessage()方法轉(zhuǎn)換成Message對(duì)象
3.Runnable 轉(zhuǎn)換的Message怕膛,Runnable 會(huì)被記錄在MSG的callback屬性上,在處理消息時(shí)柠逞,優(yōu)先被處理
3.Handler分發(fā)事件優(yōu)先級(jí)陵且,是否可以攔截聊疲?攔截的優(yōu)先級(jí)如何?
1.Handler中贡珊,通過dispatchMessage()處理消息,其中存在優(yōu)先級(jí)策略
2.優(yōu)先級(jí)1:msg.callback 寒随,run -獨(dú)占
3.優(yōu)先級(jí)2:mCallback.handlerMessage(msg) -返回值決定是非法攔截該消息
mCallback 屬于 Handler妻往,是消息的統(tǒng)?攔截機(jī)制。
3.優(yōu)先級(jí)3:handle.handleMessage()
4.Handler 在處理 Message 的時(shí)候局嘁,可以對(duì)消息統(tǒng)?攔截嗎悦昵?如何做?有什么缺點(diǎn)棋凳?
1.可以
2.實(shí)現(xiàn):使用Handler的Callback;通過Handler的構(gòu)造方法傳遞Callback對(duì)象拍棕,并實(shí)現(xiàn)其handlerMessage()方法用于Message的統(tǒng)一處理绰播。返回值表示是否攔截。
3.缺點(diǎn):無法攔截Runnable消息
5.Handler 發(fā)送延遲消息,涉及哪些?法呵萨?原理是什么?會(huì)被開機(jī)時(shí)間影響嗎忱嘹?
1.涉及方法:sendMessageDelayed()和sendMessageAtTime(),最終都會(huì)調(diào)?到 enqueueMessage() ?隊(duì)础米;
-
原理:延遲時(shí)間記錄在 msg.when 中医寿,參與 MessageQueue 的優(yōu)先級(jí)排序,即 MQ.enqueueMessage() 插?消息時(shí)沟突,會(huì)基于 when 計(jì)算消息在 MessageQueue 中的位置并插?;
image
image
3.不受開機(jī)時(shí)間影響,因其延遲消息基于 SystemClock条霜,此為設(shè)備開機(jī)時(shí)間宰睡,不受時(shí)鐘影響 旋圆。
1.prepare不同
主線程:prepareMainLooper()
子線程:prepare()
2.是否允許退出
主線程:不允許
子線程:允許
3.構(gòu)造方法不同
主線程:有ActivityThread啟動(dòng)時(shí),main()方法中構(gòu)造的刻肄,開發(fā)者無需關(guān)系
子線程:開發(fā)者執(zhí)行構(gòu)造,prepare() --->loop()
new Thread(){
public void run() {
Looper.prepare();
Toast.makeText(MainActivity.this, "Hello", 0).show();
Looper.loop();
};
}.start();
7.Looper 如何保證線程唯?绿饵?線程內(nèi)多次 prepare() 不同的 Looper 會(huì)怎樣?
1.原理:基于 TLS 機(jī)制要门,Looper ?次 prepare() 時(shí),會(huì)將 Looper 存? ThreadLocal (map)中炒瘟,再
次 prepare() 時(shí)檢查 ThreadLocal 是否已存儲(chǔ);
2.多次調(diào)? Looper prepare() 會(huì)拋出異常廓推;
8.Looper 如何判斷是否允許退出?如何設(shè)置 Looper 是否允許退出专缠?主線程 Looper 允許退出嗎?
1.判斷:Looper持有的MessageQueue的mQuitAllow狀態(tài),標(biāo)識(shí)了是否允許退出
2.設(shè)置:通過 Looper.prepare(quitAllowed) 的?參 quitAllowed 判斷是否允許退出渔工;
此?法為私有,外部?法直接調(diào)?兰吟;
3.規(guī)律:主線程 Looper 不允許退出混蔼,?線程 Looper 允許退出;
-
主線程:prepareMainLooper() → prepare(false) - 不允許退出晚吞;
image
2.其他線程:prepare() → prepare(true) - 允許退出;
9.Looper 的退出捌蚊,涉及哪些?法,原理是什么窗宦?有什么限制沐扳?
1.Api:直接退出quit() & 安全退出quitSafey()
2.原理:都會(huì)調(diào)? MessageQueue 的 quit() ?法,清理 MessageQueue 持有的消息躯嫉,并標(biāo) 記 MQ 退出哄陶,驅(qū)動(dòng)其 next() ?法返回 null蜒谤,初始 Looper 退出 loop() 循環(huán)资锰,進(jìn)?使得 Looper 退出;
3.限制:只有?線程 Looper 才允許退出,主線程 Looper 嘗試退出會(huì)拋出異常;
4.Tips:MQ 退出 → () 返回 null → Looper.loop() 收到 null → 跳出while 循環(huán) → Looper 退出鹃两;
10.Looper.loop() ?法中的循環(huán)內(nèi),調(diào)? MessageQueue 的 next(),若 next() 返回 null 則直接 退出循環(huán)梯醒,合理嗎?
1.合理
2.正常情況,MQ,next() 必然會(huì)返回待處理的消息猫胁,沒有則會(huì)通過 nativePollOnce() 休眠
3.若 next() 返回 null,則說明出現(xiàn)異常
mPtr = 0盼樟,消息隊(duì)列已被清理并退出;
mQuitting = true,消息隊(duì)列已經(jīng)被標(biāo)記為退出稍途;
11.如何構(gòu)造子線程Looper?涉及哪些方法装盯?
- 啟動(dòng)新線程迄损;
- 調(diào)? Looper.prepare() - 準(zhǔn)備垮抗;
3.調(diào)? Looper.loop() - 進(jìn)?循環(huán)液茎;
new Thread(){
public void run() {
Looper.prepare();
Toast.makeText(MainActivity.this, "Hello", 0).show();
Looper.loop();
};
}.start();
12.主線程 Looper 何時(shí)運(yùn)?欲间?
1.App啟動(dòng)時(shí),會(huì)調(diào)用到ActivityThread周达址,Looper就在其main()方法中被啟動(dòng)
2.main()中會(huì)調(diào)用Looper,prepareMainLooper()和Looper.loop()
3.Tips:ActivityThread 不繼承? Thread满葛,它只是?個(gè)運(yùn)?在主線程上的對(duì)象缠捌;
13.Message 消息池的結(jié)構(gòu)?最?緩存多少個(gè) Message 對(duì)象?
1.Message類的靜態(tài)屬性sPool維護(hù)
2.消息池基于鏈表結(jié)構(gòu)蹦魔,以msg.next串聯(lián)
3.sPoolSize 維護(hù)消息池??,最? 50;
14.Message 消息池,有什么優(yōu)點(diǎn)玩般?
1.享元模式,避免重復(fù)構(gòu)造Message
2.回收資源洒忧,回收時(shí)清理msg持有的callback和target,避免內(nèi)存泄漏
15.Handler 的 Message 可以分為那 3 類?分別有什么標(biāo)識(shí)芝雪?
1.同步Message:普通Message
2.異步Message:msg.setAsynchronous(true)
3.同步屏障:msg.target == null
16.同?個(gè) Message 對(duì)象能否重復(fù) send?
1.關(guān)鍵在于如何定義同一個(gè)Message
2.角度一:Java對(duì)象層面晤柄,可被復(fù)用
原因:Message由消息池維護(hù)芥颈,即同一個(gè)對(duì)象被回收后會(huì)被再次復(fù)用
new Message & Message.obtain()
3.角度二:業(yè)務(wù)層面盾计,不能復(fù)用署辉;
原因:Message通過enqueueMessage()入隊(duì)時(shí)炫乓,會(huì)通過markInUse()標(biāo)記,再次入隊(duì)無法通過isInUse()檢查,則會(huì)拋出異常
17.場(chǎng)景:MessageQueue 是基于觸發(fā)時(shí)間 when 的優(yōu)先級(jí)隊(duì)列安吁,那么什么情況下黔龟,隊(duì)列中靠后 的消息會(huì)優(yōu)先得到執(zhí)?巍棱?原理是什么到踏?
1.場(chǎng)景:靠前的消息是同步消息谊路,靠后的消息是異步消息,且消息隊(duì)列的隊(duì)頭為同步屏障
- 原理:同步屏障會(huì)阻塞 MQ 中的同步消息,優(yōu)先處理異步消息免都;
18.Message 的同步屏障有什么??有什么意義?如何發(fā)送?個(gè)同步屏障?
1.用途:阻塞MQ對(duì)同步Message的分發(fā),target == null ,無法通過 Handler ?隊(duì)出隊(duì)凿菩,需直接操作 MQ
2.意義:允許異步消息優(yōu)先于同步消息執(zhí)?获黔;
3.同步屏障:特殊的 Message玷氏,target == null赞辩,?法通過 Handler ?隊(duì)出隊(duì),需直接操作 MQ谷朝;
?隊(duì):postSyncBarrier():返回?個(gè)屏障 token送朱;
出隊(duì):removeSyncBarrier()
19.什么是異步消息?如何發(fā)送?
1.意義:需配合同步屏障使?垦缅,否者與同步消息?區(qū)別
-
異步消息:setAsynchronous(true) → 向 flags 添加 FLAG_ASYNCHRONOUS 標(biāo)記
image
image
3.發(fā)送?式
通過異步 Handler 發(fā)送 → 構(gòu)造 Handler 時(shí),async 傳遞 true
發(fā)送消息前,主動(dòng)調(diào)? setAsynchronous(true)
---安全起?漫试,Android 9.0 普通開發(fā)者?法使?異步消息,所有發(fā)送?式被標(biāo)記為 @hide
20.同步屏障如何配合異步消息?作?
1.當(dāng) mMessage 是?個(gè)同步屏障時(shí)勘究,會(huì)跳過所有同步消息十办,找到異步消息提前執(zhí)?
2.若 MQ 隊(duì)列中沒有異步消息,會(huì)進(jìn)? nativePollOnce(mPtr, -1) ?限等待超棺,直到同步屏障
被移除向族,或新的異步消息?隊(duì),才會(huì)通過 nativeWake() 喚醒 MQ适肠;
21.Handler 的 IdleHandler 機(jī)制,如何理解喷众?有什么?途?
1.接?斟览,需實(shí)現(xiàn) queueIdle() ?法 & 定義在 MQ 中 & 以 MQ mIdleHandlers 維護(hù)存儲(chǔ)
2.?途:可在 MQ 即將空閑時(shí),處理任務(wù)
3.邏輯點(diǎn):MQ.next() 中,當(dāng)前?待執(zhí)?消息時(shí),執(zhí)? mIdleHandlers缠诅;如上圖
4.依據(jù) queueIdle() 返回值分:持續(xù)回調(diào)(true) & ?次性回調(diào)(false),false 會(huì)導(dǎo)致執(zhí)? 完后核芽,從 mIdleHandlers 中移除 分飞。如上圖
22.IdleHandler 的 queueIdle() 返回 true,為什么不會(huì)死循環(huán)?
-
pendingIdleHandlerCount 標(biāo)記控制靠汁,MQ.next() 時(shí)概荷,初始為 -1误证;
image
2.-1 才會(huì)執(zhí)? mIdleHandlers芦昔,執(zhí)?后置為 0 → 不會(huì)重復(fù)執(zhí)?
image
3.每次 Looper.loop() 從 MQ.next() 取出消息后寡润,在 Loop 循環(huán)中繼續(xù)調(diào)? MQ.next() 才會(huì)重 置pendingIdleHandlerCount,才會(huì)繼續(xù)執(zhí)?
23.IdleHandler 執(zhí)?耗時(shí)會(huì)影響正常的消息分發(fā)嗎舅柜?Handler 內(nèi)部如何處理梭纹?
1.會(huì)
2.IdleHandler的耗時(shí)不可控
3.執(zhí)?完后會(huì)重置 nextPollTimeoutMillis = 0,重新分發(fā)最近消息
24.Handler 在 Activity 中使?致份,什么場(chǎng)景下會(huì)出現(xiàn)內(nèi)存泄露变抽?原因是什么?如何規(guī)避氮块?
1.現(xiàn)場(chǎng):延遲消息 + 內(nèi)部類 Handler绍载;導(dǎo)致Handler 持有外部類的對(duì)象
2.主線程?命周期?于四?組件,msg,target 指向 Handler滔蝉,? Handler 作為內(nèi)部類 持有外部類 Activity 的引?击儡,導(dǎo)致 Activity 泄露
- 解
1, 靜態(tài) Handler + Activity 弱引?;- 隨 Activity ?命周期锰提,onDestory() 會(huì) remove 掉所有的消息
25.移除消息的 removeMessage() 為什么需要兩次循環(huán)曙痘?
1.優(yōu)化效率
- while-1:移除消息 & 找到下?個(gè)待處理的消息芳悲,存? mMessages 中;
-
while-2:從 mMessages 開始边坤,移除后續(xù)符合條件的消息
image
25.如何理解 HandlerThread名扛?
1.繼承 Thread,內(nèi)部持有 Handler茧痒,并?維護(hù)?線程的 Looper
2.意義:將 Thread肮韧、Handler、Looper 封裝旺订,便于開發(fā)者使?
26.如何實(shí)現(xiàn)弄企,?線程等待主線程處理消息結(jié)束后,再繼續(xù)執(zhí)?区拳?原理是什么拘领?
1.借助 Handler 的 runWithScissors()
2.原理:內(nèi)部通過 BlockingRunnbale 包裝,通過 synchronized + wait 進(jìn)?等待樱调,在 r 執(zhí)?
完成后约素,調(diào)? notifyAll() 喚醒等待隊(duì)列,?線程收到后繼續(xù)執(zhí)?
27.Handler 的 runWithScissors() 可實(shí)現(xiàn) A 線程阻塞等待 B 線程處理完消息后再繼續(xù)執(zhí)?的功 能笆凌,它為什么被標(biāo)記為 hide圣猎?存在什么問題?原因是什么乞而?
1.實(shí)現(xiàn):將 Runnable 包裝為 BlockingRunnable送悔,其內(nèi)通過 synchronized + wait 進(jìn)?等
待,待 r 執(zhí)?完后爪模,調(diào)? notifyAll() 喚醒等待隊(duì)列的?線程欠啤,?線程繼續(xù)執(zhí)?(如上圖)
2.問題:在?線程 Looper 中使?,可能導(dǎo)致 A 線程進(jìn)? wait 等待呻右,?永遠(yuǎn)得不到被 notify喚醒
3.原因:?線程 Looper 允許退出跪妥,若包裝的 BlockingRunnable 被執(zhí)?前,MessageQueue
退出,則該 runnable 永遠(yuǎn)不會(huì)被執(zhí)?吧趣,則會(huì)導(dǎo)致 A 線程?直處于 wait 等待遍膜,永遠(yuǎn)不會(huì)被notify 喚醒
28.?線程如何向主線程的 Handler 發(fā)送消息?為什么經(jīng)過 Handler 就可以達(dá)到切線程的?的乒省?
1.在 Android 中,主線程主要承擔(dān)更新 UI 的?作,耗時(shí)操作?法在主線程完成
2.?作線程可以通過向主線程的 Handler 發(fā)?消息憾赁,來達(dá)到與主線程通信的?的
3.主線程與?作線程之間,是共享內(nèi)存地址空間的散吵,所以是可以互相操作的龙考,但是需要注意處理線程同步的問題
4.?作線程通過主線的 Handler蟆肆,向其成員變量 MessageQueue 中添加 Message。同時(shí)主
線程的 Looper ?直處于 loop() 狀態(tài)晦款,當(dāng)檢測(cè)到有新 Message 時(shí)炎功,會(huì)將其取出,并通過
dispatchHandler() 分發(fā)處理消息
29.Looper.loop 中缓溅,如果沒有待處理的消息蛇损,為什么不會(huì)阻塞 UI?
1.主線程在 MessageQueue 沒有消息時(shí)坛怪,會(huì)阻塞在 loop 的 queue.next() ?法中的 nativePollOnce()?法?
2.此時(shí)主線程會(huì)釋放 CPU 資源進(jìn)?休眠狀態(tài)淤齐,直到下?個(gè)消息到達(dá)或者有事務(wù)發(fā)?,通過
往 pipe 管道寫端寫?數(shù)據(jù)的?式袜匿,來喚醒主線程更啄。這?采?的是 epoll 機(jī)制
3.epoll 機(jī)制是?種 IO 多路復(fù)?機(jī)制,可以同時(shí)監(jiān)控多個(gè)描述符居灯,在有事件發(fā)?的時(shí)候祭务,?
即通知相應(yīng)程序進(jìn)?讀或?qū)懖僮鳎愃?種 callback 的回調(diào)機(jī)制穆壕。
4.主線程在?多數(shù)時(shí)候是處于休眠狀態(tài)待牵,并不會(huì)消耗?量的 CPU 資源。當(dāng)有新的消息或事
務(wù)到達(dá)時(shí)喇勋,會(huì)?即喚醒主線程進(jìn)?處理缨该,所以對(duì)?戶來說是?感知的
30.Handle MQ ?消息時(shí),為什么不出現(xiàn) ANR川背?
1.ANR 機(jī)制有獨(dú)特的覆蓋場(chǎng)景贰拿,通常原因?yàn)樘幚硐⒉患皶r(shí)
2.MQ ?消息時(shí),會(huì)進(jìn)? nativePollOnce() 休眠熄云,此時(shí)?消息膨更,處于休眠狀態(tài)
3.MQ 有消息時(shí),會(huì)?即通過 nativeWake() 喚醒去處理消息
31.如果 Java 層 MQ 中消息很少缴允,但是響應(yīng)時(shí)間卻很?荚守,是什么原因?
1.MQ隊(duì)列中练般,該Message前的Message處理較為耗時(shí)
2.Native 層消息過多矗漾,Java層MQ消息優(yōu)先級(jí)最低,最后處理
32.在完整的 Handler (Java & C++)架構(gòu)下薄料,消息處理的優(yōu)先級(jí)?
1.Native Message
2.Native Request
3.Java Message
Natitv的優(yōu)先級(jí)最高敞贡,Java的最低
33.Native 層的 MQ,提供了哪些 JNI ?法摄职?各有什么?途誊役?
nativeInit():初始化
1.創(chuàng)建了 NativeMessageQueue 對(duì)象获列,增加其引?計(jì)數(shù),并將 NativeMessageQueue
指針 mPtr 保存在 Java 層的 MessageQueue蛔垢。
2.創(chuàng)建 Native Looper 對(duì)象(如上圖)
3.調(diào)? epoll 的 epoll_create()/ epoll_ctl() 來完成對(duì) mWakeEventFd 和 mRequests 的可 讀事件監(jiān)聽击孩。
nativeDestory():回收資源
1. 調(diào)? RefBase::decStrong() 來減少對(duì)象的引?計(jì)數(shù)
2.當(dāng)引?計(jì)數(shù)為 0 時(shí),則刪除 NativeMessageQueue 對(duì)象啦桌。
nativePollOnce():利? epoll 機(jī)制休眠溯壶,等待被喚醒
調(diào)? Looper::pollOnce() 來完成,空閑時(shí)停留在 epoll_wait() ?法甫男,?于等待事件發(fā)?或 超時(shí)
//1且改、等待事件發(fā)生或者超時(shí)(timeoutMillis),如果有事件發(fā)生板驳,就從管道中讀取事件放入事件集合(eventItems)返回又跛,如果沒有事件發(fā)生,進(jìn)入休眠等待若治,如果timeoutMillis時(shí)間后還沒有被喚醒慨蓝,就會(huì)返回
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
nativeWake():向管道 mWakeEventFd 寫?字符 1,喚醒 epoll_wait() 等待
34.如何理解 Looper 的 Painter端幼?
-
在 Looper.loop() 循環(huán)消息的時(shí)候礼烈,如果 mLogging 不為 null,都會(huì)在關(guān)鍵點(diǎn)通過 Printer 輸出 Log婆跑。例如 Message 開始執(zhí)?和執(zhí)?完畢
image
2.Printer 對(duì)象在 Looper 中默認(rèn)為 null此熬,可以通過 setMessageLogging() ?法從外部設(shè)置
image
3.性能檢測(cè)?具 BlockCanary 就是利? Printer 來檢測(cè)主線程卡頓的問題。通過處理
Message 兩次 Log 的時(shí)間差值滑进,來判斷是否存在卡頓
35.Looper 的 Printer 輸出的?志犀忱,有什么其他?途?依靠的原理是什么扶关?有什么缺點(diǎn)阴汇?
1.?途:性能監(jiān)控;
2.原理:通過篩選?志內(nèi)存节槐,區(qū)分 Message 的開始執(zhí)?和結(jié)束執(zhí)?的時(shí)間點(diǎn)搀庶,即可判斷處 理 Message 的耗時(shí),即主線程卡頓耗時(shí)铜异;
3.缺點(diǎn):Printer 存在?量字符串拼接地来,在消息量?時(shí),會(huì)導(dǎo)致性能受損熙掺;
實(shí)測(cè)數(shù)據(jù):存在 Printer 時(shí),在列表快速滑動(dòng)時(shí)咕宿,平均幀率降低 5 幀币绩;
36.如何理解 epoll蜡秽?它有什么優(yōu)勢(shì)(Android M 開始,將 Pipe 換成了 eventFd)缆镣?
1.Linux 的 I/O 多路復(fù)?機(jī)制芽突,可以同時(shí)監(jiān)控多個(gè)描述符;
2.多路復(fù)?機(jī)制下董瞻,可以通知內(nèi)核掛起進(jìn)程/線程寞蚌,當(dāng) 1 個(gè) 或多個(gè) IO 事件發(fā)?后,內(nèi)核再喚 醒進(jìn)程钠糊,將控制權(quán)返還挟秤,由應(yīng)?程序??處理事件;
3.epoll 優(yōu)勢(shì):
(1)監(jiān)控描述符數(shù)量不受限抄伍;
監(jiān)控 fd 數(shù)量何內(nèi)存相關(guān)艘刚,3G 內(nèi)存 → 20w~30w
(2)IO 不會(huì)隨監(jiān)控 fd 的增多?放? → 得益于事件表維護(hù) fd 與其回調(diào)的關(guān)系;
4.epoll 適?:
1.適??量空閑連接的場(chǎng)景
2.沒有?量空閑或死亡連接時(shí)截珍,epoll 的效率不會(huì)? select/poll ? → 量?時(shí) O(logn) 和
O(n) 差別不?
5.操作
1.epoll_create - 創(chuàng)建 epoll 句柄攀甚;
2.epoll_ctl() - 設(shè)置監(jiān)聽的 fd;
3.epoll_wait() - 等待 fd 事件岗喉;
37.Handler 和管道(Pipe)的關(guān)系(Android M 開始秋度,將 Pipe 換成了 eventFd)?
1.Handler 底層的休眠機(jī)制钱床,就是利?管道 和 epoll 的 I/O 多路復(fù)?
2.線程進(jìn)?休眠荚斯,通過 nativePollOnce() 底層調(diào)? epoll_wait() 進(jìn)?休眠
3.A 線程準(zhǔn)備好 Message 后,放?消息池诞丽,向管道寫?數(shù)據(jù) “1”鲸拥,管道有數(shù)據(jù)后,會(huì)喚醒?
標(biāo)線程去處理消息
4.Tips:Android M 開始僧免,將 Pipe 換成了 eventFd刑赶;
38.Handler 底層為什么使?管道,?不是 Binder懂衩?
1.相對(duì)于同進(jìn)程內(nèi)的線程通信撞叨,Binder 太重了,浪費(fèi) CPU 和內(nèi)存資源(Binder 消耗CPU大)
2.內(nèi)存?度:Binder 通信涉及?次內(nèi)存拷?浊洞,?多個(gè)線程操作的 Handler 是在共享的內(nèi)存
中牵敷,?需拷?,只需要通知線程有數(shù)據(jù)了
3.CPU ?度:Binder 底層驅(qū)動(dòng)會(huì)維護(hù)線程池法希,?較浪費(fèi) CPU 資源
39.Handler 可以 IPC 通信(進(jìn)程間的通信)嗎枷餐?
1.不能
2.Handler 只能?于共享內(nèi)存地址的 2 個(gè)線程通信,即同進(jìn)程的 2 個(gè)線程通信苫亦;
40.Handler 為什么需要使?底層的 epoll 來休眠毛肋?
1.需要兼顧 Native 層的消息怨咪,消息可能來?底層硬件(分層方式當(dāng)中,Native層就是本地框架)
2.如果只考慮 Java 層润匙,notify/wait 即可實(shí)現(xiàn)
41.如何理解 nativePollOnce() ?法诗眨?
1.最終會(huì)調(diào)?到 Native 層的 pollInner() ?法。
2.在 pollInner() 中孕讳,處理流程:
a. 先調(diào)? epoll_wait()匠楚,這是阻塞?法,?戶等待事件發(fā)?或超時(shí)厂财。
b. 對(duì)于 epoll_wait() 返回芋簿,當(dāng)且僅當(dāng)?下三種情況出現(xiàn)時(shí),才會(huì)返回蟀苛。
POLL_ERROR益咬,發(fā)?錯(cuò)誤,直接跳轉(zhuǎn)到 Done帜平。
POLL_TIMEOUT幽告,發(fā)?超時(shí),直接跳轉(zhuǎn)到 Done裆甩。
檢測(cè)到管道有事件發(fā)?冗锁,則根據(jù)情況做響應(yīng)的處理
如果是管道有事件發(fā)?,則直接讀取管道的數(shù)據(jù)嗤栓。
如果是其他事件冻河,則處理 request,?成對(duì)應(yīng)的 response 對(duì)象茉帅,push 到
response 數(shù)組叨叙。
c. 進(jìn)? Done 標(biāo)記為的代碼段。
先處理 Native 的 Message堪澎,調(diào)? Native 的 Handler 來處理 Message擂错。
再處理 Response 數(shù)組,POLL_CALLBACK 類型的事件樱蛤。
d. 返回后钮呀,Java 層繼續(xù)處理