1. Source code analysis

For detailed analysis, please refer to code comments:

/** * Message queues are priority queues in order of execution time **@param msg
 * @param when
 * @return* /
boolean enqueueMessage(Message msg, long when) {

    // Queue messages are not bound to handlers
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    // The join message is already in use
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }

    // Get the synchronization lock
    synchronized (this) {
        // The join message is being cancelled
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            // Retrieve the queue message
            msg.recycle();
            return false;
        }
        // Mark the enqueue message as in use
        msg.markInUse();
        // Queue message execution time
        msg.when = when;
        // Get the first message of the message queue
        Message p = mMessages;
        // Whether the thread needs to be woken up
        boolean needWake;
        // If the header of the queue is null, the queue is empty
        // If the execution time of the join message is 0, the join message needs to be executed immediately
        // If the queue entry message takes less time than the queue first message
        if (p == null || when == 0 || when < p.when) {
            // New header, wake up event queue if blocked.
            // New head, wake up the event queue if blocked.
            // The join message pointer points to the first team message
            msg.next = p;
            // The team entry message becomes the new team leader message
            mMessages = msg;
            // And if the thread is blocked
            // Need to wake up
            needWake = mBlocked;
        } else {
            // Insert into the middle of the queue. Usually we do not need to wake up the event queue unless there is a barrier at the top of the queue and the message is the earliest asynchronous message in the queue.
            // 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.

            // If the thread is blocked
            If the Handler for the queue head message is empty, the queue head message is a synchronization barrier message
            // If the queued message is asynchronous, it can pass through the synchronization barrier
            // Need to wake up
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            // Previous message
            Message prev;
            / / loop
            for(; ;) {// Get the first message in the queue
                prev = p;
                // Get the next message
                p = p.next;
                // If the next message is empty, or if the execution time of the message is earlier than the next message, the loop is exited
                if (p == null || when < p.when) {
                    break;
                }
                // But if the thread is blocked
                // If there are asynchronous messages in the queue, the synchronization barrier can be crossed
                // No need to wake up

                // If the thread is blocked
                // If there are no asynchronous messages in the thread, the synchronization barrier cannot be crossed
                // Need to wake up
                if (needWake && p.isAsynchronous()) {
                    needWake = false; }}// Point the queue message to the fetched message
            msg.next = p; // invariant: p == prev.next
            // The pointer to the previous message points to the queue message
            prev.next = msg;
        }

        // We can assume mPtr! Lambda is equal to 0, because m is false.
        // We can assume mPtr ! = 0 because mQuitting is false.
        if (needWake) {
            // Wake up if you need tonativeWake(mPtr); }}return true;
}
Copy the code

2, what is the situation of the news into the team? How to join the team?

We cut out the logic of joining rules, synchronous locks, synchronous barrier messages, asynchronous messages, wake up rules, etc., and extract the logical code of joining to get:

public class Message {
    public Object obj;
    public long when;
    public Message next;
}
Copy the code
public class MessageQueue {
    public Message mMessages;

    public void enqueueMessage(Message msg, long when) {
        msg.when = when;
        Message p = mMessages;
        if (p == null || when == 0 || when < p.when) {
            // Insert messages to empty queues and queue headers
            msg.next = p;
            mMessages = msg;
        } else {
            Message prev;
            for(; ;) { prev = p; p = p.next;if (p == null || when < p.when) {
                    // Insert messages to the end and queue
                    break; } } msg.next = p; prev.next = msg; }}}Copy the code

2.1. Insert messages to an empty queue

2.2. Insert the message in the queue header

2.3. Insert the message at the end of the queue

2.4. Insert messages into the queue

When a message is queued, under what circumstances should the thread be actively awakened?

There are no messages in the queue and the thread is blocked

When a new message joins the queue, it actively wakes up the thread, no matter whether the new message is synchronous or asynchronous.

3.2 The execution time of the queue head message is not up, and the thread is blocked

If a new message is added prior to the processing time of the first queue message before the blocking time is exhausted, the thread needs to be actively woken up. 1. If the execution time of the joining message is 0, the joining message needs to be executed immediately. 2. If the execution time of the team entry message is shorter than that of the first team message, the team entry message is executed earlier than the first team message.

3.3 the queue header message is a synchronous barrier message, and the queue contains no asynchronous message, and the thread is blocked

If the new message is still added later than the synchronization obstacle of the team leader, then the new message is published at the next() level and we do not need to wake up the thread. Threads blocked by Next () are actively awakened only if a new synchronous message is added prior to the processing time of the queue leader synchronization obstacle, or if a new asynchronous message is added (regardless of the processing time).

3.4 The queue header message is a synchronous barrier message. The queue contains asynchronous messages but the execution time is not up, and the cutting thread is blocked

Whatever new synchronization messages are added will not actively wake up the thread because of the queue head synchronization obstacle. Even if an asynchronous message is added, its processing time must be earlier than the asynchronous message that is set to be executed when it is awakened.

Welcome to pay attention to the Android technology stack, focus on Android technology learning public number, dedicated to improving the Android developers professional skills!