ThreadLocal是一個線程內部的數據存儲類,經過它能夠在指定的線程中存儲數據,數據存儲之後,只有在指定的線程中能夠獲取到存儲的數據,對於其餘線程來講則沒法獲取到數據數組
當某些數據以線程爲做用域而且不一樣線程具體不一樣的數據副本,能夠考慮使用ThreadLocal安全
6.0之前實現bash
set()數據結構
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
首先拿到當前線程localValues,若是localValues沒有值,就會初始化一個Values;
Values中有一個Object[],其實這個數組是一個以key-value的方式來存放threadLocal.set()進來的值;
在數組中key對應的是threadLocal.reference,key的index是經過 threadLocal.hash & threadLocal.mask 計算出來的值
在數組中value對應的就是ThreadLocal.set()進來的值,value的index就是key的index的下一位即index+1
key的index元素說明:reference、hash & mask
reference = new WeakReference<ThreadLocal<T>>(this);this-->ThreadLocal
hash = hashCounter.getAndAdd(0x61c88647 * 2);
hashCounter = new AtomicInteger(0);原子操做Integer的類,高併發安全
mask = Object[].length-1
複製代碼
get()併發
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
複製代碼
7.0之後的實現高併發
set()oop
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
與以前不一樣的就是Value實現改成了ThreadLocalMap,將以前的thread.localValues改爲了threadLocals;
首先拿到當前線程threadLocals,若是localValues沒有值,就會初始化一個ThreadLocalMap;
ThreadLocalMap中有一個Entry[],這個Entry是一個以key-value的方式來存放threadLocal.set()進來的值;
Entry繼承自WeakReference<ThreadLocal>
key存放的就是ThreadLocal,內部仍是存放了一個weakReference,泛型爲ThreadLocal
value存放的就是set進來的值
entry的index仍是經過 threadLocal.hash & threadLocal.mask 計算出來的
複製代碼
get()post
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
複製代碼
不停地從MessageQueue中查看是否有新消息,有的話馬上處理,不然一直阻塞ui
能夠經過Looper.prepare()爲當前線程建立一個looper,經過loop方法開啓消息輪詢this
Looper也是能夠退出的,提供了quit()和quitSafely();
Looper退出之後,handler會發送失敗,send()返回false
loop()方法是一個死循環,惟一跳出循環的方式就是MessageQueue.next()方法返回null
當looper的quit方法被調用的時候就會調用MessageQueue的quit或者quitSafely方法通知消息隊列退出,不然loop()方法就會無限循環下去
當沒有消息時,next方法一直阻塞,致使loop方法阻塞
若是next方法返回了消息,Looper就會處理,msg.target.dispatchMessage(msg)
進入死循環以前便建立了新Binder線程,建立一個Binder線程(具體是指ApplicationThread,Binder的服務端,用於接收系統服務AMS發送來的事件),該Binder線程經過Handler將Message發送給主線程
ActivityThread經過ApplicationThread和AMS進行進程間通訊,AMS以進程間通訊的方式完成ActivityThread的請求後回調ApplicationThread中的Binder方法,而後ApplicationThread會向H發送消息,H收到消息後會將ApplicationThread中的邏輯切換到ActivityThread中去執行,即切換到主線程中執行,這個過程就是主線程的消息循環模型