之前有一章節介紹了Handler的常見面試題,今天就來說說另類的,可能你沒關注的其他問題,一起看看吧,
系統為什么提供Handler
- 這點大家應該都知道一些,就是為了切換執行緒,主要就是為了解決在子執行緒無法訪問UI的問題,
那么為什么系統不允許在子執行緒中訪問UI呢?
- 因為
Android的UI控制元件不是執行緒安全的,所以采用單執行緒模型來處理UI操作,通過Handler切換UI訪問的執行緒即可,
那么為什么不給UI控制元件加鎖呢?
- 因為加鎖會讓
UI訪問的邏輯變得復雜,而且會降低UI訪問的效率,阻塞執行緒執行,
Handler是怎么獲取到當前執行緒的Looper的
- 大家應該都知道
Looper是系結到執行緒上的,他的作用域就是執行緒,而且不同執行緒具有不同的Looper,也就是要從不同的執行緒取出執行緒中的Looper物件,這里用到的就是ThreadLocal,
假設我們不知道有這個類,如果要完成這樣一個需求,從不同的執行緒獲取執行緒中的Looper,是不是可以采用一個全域物件,比如hashmap,用來存盤執行緒和對應的Looper?所以需要一個管理Looper的類,但是,執行緒中并不止這一個要存盤和獲取的資料,還有可能有其他的需求,也是跟執行緒所系結的,所以,我們的系統就設計出了ThreadLocal這種工具類,
ThreadLocal的作業流程是這樣的:我們從不同的執行緒可以訪問同一個ThreadLocal的get方法,然后ThreadLocal會從各自的執行緒中取出一個陣列,然后再陣列中通過ThreadLocal的索引找出對應的value值,具體邏輯呢,我們還是看看代碼,分別是ThreadLocal的get方法和set方法:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
首先看看set方法,獲取到當前執行緒,然后取出執行緒中的threadLocals變數,是一個ThreadLocalMap類,然后將當前的ThreadLocal作為key,要設定的值作為value存到這個map中,
get方法就同理了,還是獲取到當前執行緒,然后取出執行緒中的ThreadLocalMap實體,然后從中取到當前ThreadLocal對應的值,
其實可以看到,操作的物件都是執行緒中的ThreadLocalMap實體,也就是讀寫操作都只限制在執行緒內部,這也就是ThreadLocal故意設計的精妙之處了,他可以在不同的執行緒進行讀寫資料而且執行緒之間互不干擾,
畫個圖方便理解記憶:

當MessageQueue 沒有訊息的時候,在干什么,會占用CPU資源嗎,
MessageQueue沒有訊息時,便阻塞在 loop 的queue.next()方法這里,具體就是會呼叫到nativePollOnce方法里,最終呼叫到epoll_wait()進行阻塞等待,
這時,主執行緒會進行休眠狀態,也就不會消耗CPU資源,當下個訊息到達的時候,就會通過pipe管道寫入資料然后喚醒主執行緒進行作業,
這里涉及到阻塞和喚醒的機制叫做 epoll 機制,
先說說檔案描述符和I/O多路復用:
在Linux作業系統中,可以將一切都看作是檔案,而檔案描述符簡稱fd,當程式打開一個現有檔案或者創建一個新檔案時,內核向行程回傳一個檔案描述符,可以理解為一個索引值,
I/O多路復用是一種機制,讓單個行程可以監視多個檔案描述符,一旦某個描述符就緒(一般是讀就緒或寫就緒),能夠通知程式進行相應的讀寫操作
所以I/O多路復用其實就是一種監聽讀寫的通知機制,而Linux提供的三種 IO 復用方式分別是:select、poll 和 epoll ,而這其中epoll是性能最好的多路I/O就緒通知方法,
所以,這里用到的epoll其實就是一種I/O多路復用方式,用來監控多個檔案描述符的I/O事件,通過epoll_wait方法等待I/O事件,如果當前沒有可用的事件則阻塞呼叫執行緒,
拜拜
今天就說這么多了,感興趣的朋友也可以繼續深究下去,比如epoll為什么是性能最好的I/O多路復用方法?Handler在App啟動流程中涉及到了哪些功能?等等,有機會再和大家聊聊~
有一起學習的小伙伴可以關注下??我的公眾號——碼上積木,每天剖析一個知識點,我們一起積累知識,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/225274.html
標籤:Android
上一篇:關于使用QT開發的討論

