以前有一章節介紹了Handler的常見面試題,今天就來講說另類的,可能你沒關注的其餘問題,一塊兒看看吧。java
那麼爲何系統不容許
在子線程中訪問UI呢?面試
Android
的UI控件不是線程安全的,因此採用單線程模型來處理UI操做,經過Handler切換UI訪問的線程便可。那麼爲何不給UI控件加鎖
呢?數組
UI
訪問的邏輯變得複雜,並且會下降UI
訪問的效率,阻塞線程執行。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中。oop
get方法
就同理了,仍是獲取到當前線程,而後取出線程中的ThreadLocalMap
實例,而後從中取到當前ThreadLocal
對應的值。性能
其實能夠看到,操做的對象都是線程中的ThreadLocalMap
實例,也就是讀寫操做都只限制在線程內部,這也就是ThreadLocal
故意設計的精妙之處了,他能夠在不一樣的線程進行讀寫數據並且線程之間互不干擾。學習
畫個圖方便理解記憶:this
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啓動流程中涉及到了哪些功能?等等。有機會再和你們聊聊~
有一塊兒學習的小夥伴能夠關注下❤️個人公衆號——碼上積木,天天剖析一個知識點,咱們一塊兒積累知識。