Handle机制

Handle源码

  1. 生产者消费者模式:多线程并发协作的模式,处理数据同步问题。 www.jianshu.com/p/29c1909cb…
  • a. 生产者产生的数据到缓存区,消费者从缓存区取数据
  • b.如果缓存区已满,则生产者线程阻塞
  • c. 如果缓存为空,则消费者线程阻塞

2.缓存队列的处理:

  • linkHashmap + synchronice + wait + notifyAll
  • linkHashmap + lock (await,signalAll)
  • 直接阻塞队列 BlockingQueue
  1. 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();

blog.csdn.net/u013008419/…

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
喜欢就支持一下吧
点赞0 分享