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!