Handler發(fā)送Message流程
- 從主線程
new Handler()
開始:
<Handler.java>
public Handler() {
this(null, false);
}
public Handler(@Nullable Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
// 獲取當(dāng)前線程的looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// 獲取當(dāng)前線程的messageQueue
mQueue = mLooper.mQueue;
mCallback = callback;// 回調(diào)
mAsynchronous = async;// 設(shè)置異步標(biāo)記,異步消息會優(yōu)先處理
}
<Lopper.java>
// 通過ThreadLocal保證每個線程只有一個looper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
- 主線程的
Looper
是在應(yīng)用程序啟動時ActivityThread
為我們創(chuàng)默認(rèn)創(chuàng)建了肖粮,所以上面new Handler()
中可以直接獲取到主線程的Looper
:
<ActivityThread.java>
public static void main(String[] args) {
...
// 構(gòu)造主線程Looper對象
Looper.prepareMainLooper();
...
...
// 應(yīng)用運行期間所有代碼都運行在此位置,如果主線程Looper退出循環(huán),則應(yīng)用運行結(jié)束
// 開啟消息循環(huán)
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
-
Looper
初始化和準(zhǔn)備過程
<Looper.java>
public static void prepareMainLooper() {
// 創(chuàng)建實例
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
// 變量賦值
sMainLooper = myLooper();
}
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {// 一個線程只能有一個Looper
throw new RuntimeException("Only one Looper may be created per thread");
}
// new了一個Looper對象
sThreadLocal.set(new Looper(quitAllowed));
}
// 開始死循環(huán)獲取消息
public static void loop() {
final Looper me = myLooper();// 獲取當(dāng)前線程looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;// 獲取到當(dāng)前消息隊列
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
// 開啟死循環(huán)輪詢消息
for (;;) {
// 從消息隊列中獲取下一個未處理的消息,重點愁溜,后面分析
Message msg = queue.next(); // might block
// 消息隊列為空,沒有消息了外厂,此時說明退出應(yīng)用了
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
// 消息分發(fā)回調(diào)給handler處理
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
}
...
// 回收消息加入復(fù)用池
msg.recycleUnchecked();
}
}
-
new Handler()
以及主線程Looper
的初始化和準(zhǔn)備工作已經(jīng)完成冕象,接下去就是常見的發(fā)送消息
<Handler.java>
// Message的復(fù)用機(jī)制下面再分析
handler.sendMessage(Message.obtain());
// 發(fā)送消息
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
// 發(fā)送消息如果不設(shè)置延時,內(nèi)部設(shè)置為0
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
// 時間的基數(shù)為當(dāng)前系統(tǒng)啟動時間汁蝶,即使delay=0渐扮,實際上uptimeMillis也是>0
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
// 不論是post论悴,sendEmptyMessage等最終都是走到這里
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;// 當(dāng)前線程消息隊列
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
// 將消息按時間放入隊列中
return enqueueMessage(queue, msg, uptimeMillis);
}
// 將消息添加到消息隊列
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
// target賦值給當(dāng)前handler,所以message持有當(dāng)前handler的引用墓律,一般情況new Handler匿名內(nèi)部類持有外部Activity引用膀估,而MessageQueue持有Message引用,從而產(chǎn)生生命周期比Activity長的引用鏈耻讽,因此會導(dǎo)致Activity內(nèi)存泄露(普通匿名內(nèi)部類一般不會導(dǎo)致內(nèi)存泄露)
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
// 如果是異步消息察纯,設(shè)置標(biāo)記位FLAG_ASYNCHRONOUS
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 最終調(diào)用MessageQueue的enqueueMessage方法,將當(dāng)前消息放到隊列的尾部
return queue.enqueueMessage(msg, uptimeMillis);
}
- 接下去就是將消息放入消息隊列针肥,等待消息的輪詢處理
<MessageQueue.java>
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
// 注意饼记,同步鎖!為了處理多個線程中Handler發(fā)送消息的并發(fā)處理
synchronized (this) {
// 當(dāng)前Looper正在執(zhí)行quit操作慰枕,也是調(diào)用MessageQueue的quit具则,此時發(fā)送消息沒必要處理了
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
// 回收消息
msg.recycle();
return false;
}
msg.markInUse();// 標(biāo)記當(dāng)前消息正在處理
msg.when = when;// 當(dāng)前消息的需處理時間
// ----->>>> 重點:消息入隊及排序
Message p = mMessages;// 當(dāng)前消息隊頭
boolean needWake;// 是否需要喚醒,一般不需要用戶去主動去喚醒具帮,除非無消息了長期休眠
// 1. p = null說明當(dāng)前隊列沒有消息博肋,直接插入到隊頭(通常這種場景)
// 2. when==0只有Handler調(diào)用sendMessageAtFrontOfQueue時成立
// 3. when < p.when說明當(dāng)前消息時間小于隊頭消息的時間,需要插到最前面
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;// msg插入到隊頭:msg->p->...
mMessages = msg;// 刷新當(dāng)前隊頭
needWake = mBlocked;// 上次取消息時蜂厅,隊列沒有消息了束昵,mBlocked=true并且掛起,所以此刻需要喚醒
} else {// 當(dāng)前隊列中已經(jīng)存在其他未處理消息葛峻,mBlocked=false
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
// 同步屏障消息
needWake = mBlocked && p.target == null && msg.isAsynchronous();// 一般是false
Message prev;// 定義上一個消息
for (;;) {// 循環(huán)遍歷
prev = p;// 將當(dāng)前隊頭賦值給上個消息
p = p.next;// 將之前的隊頭的下一個消息賦值給p
// 1. msg1 -> msg2(假設(shè)當(dāng)前隊列中有兩個消息锹雏,msg1是當(dāng)前隊頭)
// 2. 定義一個變量p = msg1
// 3. 定義一個變量pre = p, 也就是pre = msg1
// 4. p = msg1, p.next = msg1.next = msg2, 所以p = msg2
// 5. 此時消息順序: pre -> p
// 6. 不斷循環(huán)上述操作,pre和p一直往后移動:pre是倒數(shù)第二個术奖,p是隊尾
if (p == null || when < p.when) {
// p==null說明已經(jīng)是隊列的尾部了
// when<p.when說明當(dāng)前消息處理時間比當(dāng)前隊尾的消息要早礁遵,需要排到p的前面
break;
}
// 一般needWake=false進(jìn)不來
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 上面循環(huán)排序后獲取到的pre是倒數(shù)第二個消息,p是最后一個消息
// 將當(dāng)前發(fā)送的消息插入到當(dāng)前遍歷到的隊尾(p不一定是整個隊列最后的消息):
// pre->msg->p || pre->msg->p->...
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
// native層喚醒采记,停止next方法中的阻塞nativePollOnce佣耐,立刻獲取消息
nativeWake(mPtr);
}
}
return true;
}
- 正常情況下至此,消息已經(jīng)發(fā)送并且成功加入到
MessageQueue
的隊尾了唧龄,接下去就是消息的輪詢處理了兼砖,上面已經(jīng)提到了Looper.loop()
方法,內(nèi)部是個死循環(huán)既棺,不斷調(diào)用MessageQueue.next()
去獲取下一個消息
<Looper.java>
// 開啟死循環(huán)輪詢消息
for (;;) {
// 從消息隊列中獲取下一個未處理的消息讽挟,重點,后面分析
Message msg = queue.next(); // might block
// 消息隊列為空丸冕,沒有消息了耽梅,此時說明退出應(yīng)用了
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
// 消息分發(fā)回調(diào)給handler處理
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
}
...
// 回收消息加入復(fù)用池
msg.recycleUnchecked();
}
<MessageQueue.java>
// 獲取下一個消息
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;// native層的MessageQueue的指針
if (ptr == 0) {
return null;// native退出了或者掛了,epoll機(jī)制已經(jīng)無效了胖烛,還玩啥?
}
// 這個值會影響下面的mBlocked標(biāo)記
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
// 同樣是個死循環(huán)
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// 此處可能會阻塞眼姐,但是不會導(dǎo)致應(yīng)用卡死(應(yīng)用卡死是ANR)
// 阻塞過程會休眠cpu(linux機(jī)制)诅迷,節(jié)約系統(tǒng)資源
// 阻塞不會一直延續(xù),會在超時后自動喚醒众旗,touch事件或者調(diào)用nativeWait會主動喚醒休眠
nativePollOnce(ptr, nextPollTimeoutMillis);
// 注意罢杉,消息入隊同步鎖,取消息同樣有同步鎖贡歧,都是為了處理多線程并發(fā)問題
// 此處也說明當(dāng)前隊列的消息并不是完全準(zhǔn)確的按照delayTime處理滩租,可能存在延時
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();// 當(dāng)前系統(tǒng)啟動時間
Message prevMsg = null;// 定義上一個消息prevMsg
Message msg = mMessages;// 當(dāng)前消息隊頭
// msg.target==null說明是postSyncBarrier方式發(fā)送的同步屏障消息,非一般通過handler的sendMessage發(fā)送出來
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;// 不斷往后遍歷艘款,msg為當(dāng)前遍歷的隊尾,直到找到最前面的異步消息
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {// msg為當(dāng)前隊頭或者異步消息
if (now < msg.when) {// 隊頭消息的時間都還沒到沃琅,暫時不需要處理哗咆,計算下一次喚醒時間
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);// 計算本次阻塞到下次喚醒的時長
} else {// 到時間了,需要取出消息處理
// Got a message.
mBlocked = false;// 說明有消息存在益眉,不需要阻塞
if (prevMsg != null) {// 同步屏障消息的場景晌柬,msg為最靠前的異步消息
prevMsg.next = msg.next;// 取出了隊列中間最前的異步消息,重新鏈接隊列鏈表
} else {
mMessages = msg.next;// 之前的隊頭已經(jīng)取出來處理了郭脂,隊頭后移一個
}
msg.next = null;// msg已經(jīng)從隊列中取出
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();// 標(biāo)記msg正在使用
return msg;// 取出需要處理的消息年碘,返回
}
} else {// msg為空,沒有消息了展鸡,需要一直掛起
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {// 正在退出屿衅,返回null
dispose();
return null;
}
// 假設(shè)上面沒有return message,說明當(dāng)前隊列沒有需要處理的消息(沒有消息或者需要處理的時間未到)莹弊,則開始執(zhí)行idleHandler
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0 // 上面初始值為-1
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();// 獲取idleHandlers容量
}
if (pendingIdleHandlerCount <= 0) {// 沒有idleHandler需要執(zhí)行
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
// 走到這說明沒有return message涤久,也沒有idleHandler需要執(zhí)行,所以要阻塞
// 此時nextPollTimeoutMillis = -1會一直阻塞直到被主動喚醒
continue;
}
// 初始化idleHandlers
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// 執(zhí)行空閑idleHandler
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();// 是否一次性的標(biāo)志忍弛,具體執(zhí)行
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);// 一次性執(zhí)行后移除
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;// 上面已經(jīng)執(zhí)行過了idleHandler响迂,所以賦值0,所以for死循環(huán)中不會再執(zhí)行
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;// idleHandler執(zhí)行后立即喚醒细疚,可能有延時消息到了處理時機(jī)
}
}
- 取出消息后蔗彤,再回去看
Looper.loop()
里對消息的分發(fā)
<Looper.java>
public static void loop() {
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {// 沒消息說明當(dāng)前已經(jīng)調(diào)用了quit退出循環(huán)
// No message indicates that the message queue is quitting.
return;
}
...
try {
msg.target.dispatchMessage(msg);// msg的target就是Handler,回調(diào)handler的dispatchMessage方法
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
msg.recycleUnchecked();
}
}
<Handler.java>
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);// 如果msg有自己的callback疯兼,執(zhí)行msg的callback然遏,一般情況下callback都為null
} else {
if (mCallback != null) {// 這個mCallback對于app來說是無法使用的,google已經(jīng)添加了注解 @UnsupportedAppUsage
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);// 所以吧彪,通常情況就走到這里了啦鸣,回調(diào)消息處理
}
}
// Message.obtain方法有一個重載,內(nèi)部有兩個參數(shù):
// public static Message obtain(Handler h, Runnable callback) {...}
private static void handleCallback(Message message) {
message.callback.run();// 執(zhí)行callback的run方法
}
- 至此来氧,整個消息分發(fā)處理流程已經(jīng)分析結(jié)束诫给∠憷總結(jié)如下:
-
Looper.prepare
->new Looper
對象并添加到ThreadLocal
保存 -
Looper
構(gòu)造函數(shù)中 ->new MessageQueue
創(chuàng)建消息隊列 -
Looper.loop
-> 開啟死循環(huán)輪詢,不斷調(diào)用MessageQueue.next
-
MessageQueue.next()
獲取下一條需要處理的消息中狂,無消息或者還未到處理時間則阻塞休眠 -
Handler.sendMessage
->Handler.enqueueMessage
->MessageQueue.enqueueMessage
將消息添加到隊列 -
Looper.loop
循環(huán)中通過MessageQueue.next
取出發(fā)送的消息 ->Msg
-
Msg.target(Handler).dispatchMessage
->Handler.handleMessage
- 當(dāng)消息隊列沒有消息時會持續(xù)掛起凫碌,下一條消息來了會觸發(fā)主動喚醒
- 正常情況下系統(tǒng)會根據(jù)當(dāng)前時間和隊頭消息的處理時間計算出下次喚醒的時間,不需要主動觸發(fā)喚醒
Message的復(fù)用機(jī)制
-
Message
是可以通過new
的方式來進(jìn)行創(chuàng)建胃榕,但是該方式就會在堆區(qū)申請內(nèi)存空間盛险,android
系統(tǒng)內(nèi)部充斥著大量消息,如果每個消息都通過該方式進(jìn)行創(chuàng)建勋又,該消息處理完后會產(chǎn)生大量的垃圾碎片苦掘,造成內(nèi)存抖動,頻繁gc
楔壤,嚴(yán)重影響性能鹤啡。因此,內(nèi)部通過一個緩存池進(jìn)行復(fù)用(鏈表結(jié)構(gòu))
<Message.java>
public static final Object sPoolSync = new Object();// 同步對象鎖
private static Message sPool;// 消息隊列中的隊頭(也可以稱為緩存池蹲嚣,message自身是鏈表結(jié)構(gòu)递瑰,next指向下一條消息)
private static int sPoolSize = 0;// 當(dāng)前緩存池大小
private static final int MAX_POOL_SIZE = 50;// 最多緩存50個消息
@UnsupportedAppUsage
/*package*/ Message next;
// 享元設(shè)計模式,對象共享隙畜,只是擦除內(nèi)部屬性
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {// 同步處理
if (sPool != null) {// 緩存池為空
// 從message鏈表結(jié)構(gòu)中取出隊頭的message給外部使用抖部,同時將sPool指向新的隊頭
Message m = sPool;
sPool = m.next;
m.next = null;// 擦除內(nèi)部標(biāo)記,斷開消息鏈
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;// 返回該消息對象
}
}
return new Message();
}
// sPool緩存池的創(chuàng)建初始化议惰,系統(tǒng)調(diào)用
/**
* Recycles a Message that may be in-use.
* Used internally by the MessageQueue and Looper when disposing of queued Messages.
*/
@UnsupportedAppUsage
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {// 同步處理
if (sPoolSize < MAX_POOL_SIZE) {// 當(dāng)前容量小于最大容量50
next = sPool;// sPool賦值給next
sPool = this;// 當(dāng)前消息賦值給sPool:sPool->當(dāng)前msg->next... 下次復(fù)用的永遠(yuǎn)是隊頭的消息
sPoolSize++;// 容量+1
}
}
}
Looper線程單例原理
核心類就是ThreadLocal
慎颗,它提供線程局部變量,每個線程都有自己獨立的一份變量言询,通常是類中的 private static
字段哗总,它們希望將狀態(tài)與某一個線程相關(guān)聯(lián),在多線程編程中常用倍试,比如Android
的繪制同步機(jī)制Choreographer
中也有使用讯屈。
<Looper.java>
@UnsupportedAppUsage
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
// 會判斷,如果之前ThreadLocal已經(jīng)存在Looper對象县习,拋出異常涮母,一個線程只能有一個Looper
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
<ThreadLocal.java>
public void set(T value) {
Thread t = Thread.currentThread();// 獲取當(dāng)前線程
ThreadLocalMap map = getMap(t);// 獲取當(dāng)前線程的ThreadLocalMap,默認(rèn)為null
if (map != null)// 當(dāng)前線程已經(jīng)初始化了ThreadLocalMap
map.set(this, value);// key為當(dāng)前ThreadLoacl
else
createMap(t, value);// 延遲躁愿,第一次set時候才進(jìn)行初始化
}
void createMap(Thread t, T firstValue) {
// ThreadLocalMap和當(dāng)前線程綁定叛本,保證線程唯一性
t.threadLocals = new ThreadLocalMap(this, firstValue);// 創(chuàng)建ThreadLocalMap,并且添加初始值
}
static class ThreadLocalMap {
// 構(gòu)造函數(shù)會存儲第一次賦值
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;// 存儲的值
Entry(ThreadLocal<?> k, Object v) {
super(k);// 弱引用緩存當(dāng)前ThreadLocal對象
value = v;// 存儲的值
}
//Entry.get() == null表示key不再被引用彤钟,表示ThreadLocal對象被回收
}
private Entry[] table;// 緩存key-value的數(shù)組
// setter賦值
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;// 緩存數(shù)組
int len = tab.length;// 當(dāng)前容量
int i = key.threadLocalHashCode & (len-1);// 生成索引来候,新增一個就會變化
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {// 當(dāng)前ThreadLocal對象為key,如果相等覆蓋之前的value值
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);// 加入緩存
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
// getter取值
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);// 生成索引逸雹,規(guī)則同set方法
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
}
public T get() {
Thread t = Thread.currentThread();// 獲取當(dāng)前線程
ThreadLocalMap map = getMap(t);// ThreadLocalMap和線程Thread唯一對應(yīng)营搅,所以get操作只有當(dāng)前線程可以訪問
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);// 根據(jù)key獲取entry
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;// 取出value值
return result;
}
}
return setInitialValue();
}
- 小結(jié)一下set和get流程云挟,里面具體的hash映射算法和索引計算法未分析,看不懂(線性探測法尋址)
-
ThreadLocal.set()
->getMap() or createMap()
返回當(dāng)前Thread
的ThreadLocalMap
- 當(dāng)前
Thread
的ThreadLocalMap.put(ThreadLocal, value)
存入數(shù)據(jù)转质,其中key
就是ThreadLoacal
-
ThreadLocal.get()
->getMap()
返回當(dāng)前Thread
的ThreadLocalMap
- 當(dāng)前
Thread
的ThreadLocalMap.get(ThreadLocal)
讀取數(shù)據(jù)
-
ThreadLocal
使用不當(dāng)會出現(xiàn)內(nèi)存泄露园欣,出現(xiàn)內(nèi)存泄露需同時滿足以下三個條件:
-
ThreadLocal
引用被設(shè)置為null
,且后面沒有set休蟹,get,remove
操作沸枯,該entry
變成游離狀態(tài) - 線程一直運行,不停止(線程池)
- 觸發(fā)了垃圾回收(
Minor GC
或Full GC
)
-
Android Looper
中并沒有調(diào)用ThreadLocal
的remove
赂弓,為何不會出現(xiàn)內(nèi)存泄露呢绑榴?主要有以下原因:
Looper
中的ThreadLocal
使用static final
修飾,static
修飾的生命周期與Application
同在盈魁,Application
退出時線程自然停止運行了翔怎,并且final
修飾其他地方無法修改其引用。因此同時打破了上面的條件1,2备埃,不會出現(xiàn)ThreadLocalMap
存儲數(shù)組中key
為null
時觸發(fā)GC
的內(nèi)存泄露問題
總結(jié)一下姓惑,由Handler
引申出來的知識點包括以下:
-
Handler
發(fā)送消息流程褐奴,與Looper按脚,MessageQueue
三者之間角色關(guān)系 -
Handler
內(nèi)存泄露原因以及處理方案 -
MessageQueue
數(shù)據(jù)結(jié)構(gòu),鏈表和隊列區(qū)別敦冬,Message
入隊和出隊的遍歷方法 -
Looper
如何保證線程變量唯一辅搬,ThreadLocal
原理和內(nèi)存泄露 -
ThreadLocal
內(nèi)存泄露引申出弱引用,軟引用和強(qiáng)引用 -
Message
消息的復(fù)用機(jī)制脖旱,緩存原理堪遂,鏈表結(jié)構(gòu) -
Message
設(shè)計復(fù)用機(jī)制的原因,內(nèi)存抖動萌庆,享元設(shè)計模式 - 消息屏障
Barrier
是如何保證優(yōu)先執(zhí)行的溶褪,以及系統(tǒng)內(nèi)部應(yīng)用場景 -
Android
中應(yīng)用卡死的定義,ANR -
MessageQueue
死循環(huán)節(jié)約資源處理方案践险,linux
的ePoll
機(jī)制 -
IdleHandler
的作用猿妈,和處理時機(jī),處理方式