Handle源码
- 生产者消费者模式:多线程并发协作的模式,处理数据同步问题。 www.jianshu.com/p/29c1909cb…
- a. 生产者产生的数据到缓存区,消费者从缓存区取数据
- b.如果缓存区已满,则生产者线程阻塞
- c. 如果缓存为空,则消费者线程阻塞
2.缓存队列的处理:
- linkHashmap + synchronice + wait + notifyAll
- linkHashmap + lock (await,signalAll)
- 直接阻塞队列 BlockingQueue
- looper、MessageQueue、handle、Message www.zhihu.com/question/34…
1. Message (内含回收缓存池)
private static final Object spoolSync =new Object();
private static final int MAX_POOL_SIZE = 50;
public void recycleUnchecked(){
// 清空message的其他信息 非缓存池相关的变量都置空
what=0;
target=null;
callback=null................;
synchronic(spoolSync){
if(spoolsize < MAX_POOL_SIZE){
next = spool;
spool = this;
spoolsize++;
}
}
}
// 避免对象的重复创建
public static void obtain(){
synchronic(spoolSync){
if(spool != null ){
Message m = spool;
spool = m.next;
m.next = null;
return m;
}
return new Message();
}
}
复制代码
2. MessageQuene
提供SyncBarrier(同步障碍器) 与IdleHandler闲时任务机制。见 messageQueue.next();
enqueueMessage()
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
synchronized (this) {
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();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 将链表按照时间从小到大依次排列
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
//
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
复制代码
总结:1.messageQueue实质上通过一个单向链表(mMessage),对消息进行入列和出列操作。入列:如果mMessage没有消息的就会把这条消息插入到链表的头部。此时队列如果是阻塞的,就唤醒队列。这也解释了 轮询消息时候,队列阻塞了会等待消息唤醒(轮询消息时,消息为空会阻塞队列)。2.通过循环操作,将链表按照时间从小到大依次排列,这也保证了消息处理的顺序。
Message next()
` public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
}`
Message next() {
for (;;) {
// nextPollTimeoutMillis(0:默认值,不阻塞,-1:阻塞,等待新消息唤醒,>1:阻塞,阻塞timeout后唤醒)
nativePollOnce(ptr, nextPollTimeoutMillis);
}
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
// 同步屏蔽消息时 target 没有值
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous()); // 不是异步消息
}
if (msg != null) {
if (now < msg.when) {
// 该条消息还未执行的时间,会阻塞队列,timeout后会自动唤醒队列
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// 没有消息时,会阻塞队列,等待新消息进入后唤醒
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// 没有消息处理时,线程空闲了处理idlehandle ,根据keep决定触发后 是否remove改idlehandle
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();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
复制代码
总结:1.首先处理同步屏蔽消息,如果消息是同步屏蔽时,并且是异步消息时,会优先处理此消息。2.如果该条消息还未到该执行的时间,就会阻塞队列timeout后会自动唤醒队列。3.如果消息为空(消息队列闲暇),会阻塞队列等待新的消息进入唤醒队列,idleHandle也会唤醒队列。idleHandle在消息队列闲暇时触发,不能处理耗时的操作。返回值,决定触发后会不会再次触发。
3.ThreadLocal
1.多线程并发,每个线程都有自己的局部变量,这些线程和其他线程无关。如果放到全局变量,就需要加锁保护。此时,可以在线程内部,通过ThreadLocal保存局部变量。ThreadLocal以空间换取时间,synchronic通过时间换空间。2.使用完毕需要释放remove,防止产生OOM。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END