Handle the source code
- Producer-consumer pattern: A multi-threaded concurrent collaboration pattern that deals with data synchronization. www.jianshu.com/p/29c1909cb…
- A. The producer generates the data into the cache, and the consumer retrives the data from the cache
- B. If the cache is full, the producer thread blocks
- C. If the cache is empty, the consumer thread blocks
2. Cache queue processing:
- linkHashmap + synchronice + wait + notifyAll
- linkHashmap + lock (await,signalAll)
- Block queue BlockingQueue directly
- Stars, MessageQueue, handle, Message www.zhihu.com/question/34…
1. Message (contains reclaim cache pool)
private static final Object spoolSync =new Object(); private static final int MAX_POOL_SIZE = 50; Public void recycleUnchecked(){// Empty other information about the message that is not the cache pool related variables are empty 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(); }}Copy the code
2. MessageQuene
Provides SyncBarrier and IdleHandler for idle tasks. See 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; // Arrange the list in order of time from smallest to largest. { 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; }Copy the code
Conclusion: 1. MessageQueue is essentially a one-way linked list (mMessage), which carries out the operation of message entry and exit. Inline: If mMessage does not have a message, it inserts the message to the head of the list. If the queue is blocked, the queue is woken up. This also explains why, when polling for messages, the queue is blocked waiting for the message to wake up (when polling for messages, the queue is blocked if the message is empty). 2. Through a loop operation, the linked list is arranged in chronological order, which also ensures the order of message processing.
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: default, do not block, -1: block, wait for a new message to wake up, >1: block, wake up after 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 has no value if (MSG! = null && msg.target == null) { do { prevMsg = msg; msg = msg.next; } while (msg ! = null && ! msg.isAsynchronous()); } if (MSG! = null) {if (now < msg.when) {// This message is not executed time, will block the queue, 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; NextPollTimeoutMillis = -1; 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); If (int I = 0; if (int I = 0; if (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; }}Copy the code
Summary: 1. The synchronous masked message is processed first. If the message is synchronous masked and asynchronous, the message is processed first. 2. If the message does not reach the execution time, the queue will be blocked and the queue will wake up automatically after timeout. 3. If the message is empty (message queue idle), the queue will be blocked until a new message enters the wake queue. IdleHandle will also wake up the queue. The idleHandle is triggered when the message queue is idle and cannot process time-consuming operations. Returns a value that determines whether it will fire again.
3.ThreadLocal
1. Multi-threading concurrency, each thread has its own local variables, these threads and other threads are independent. If you put it in a global variable, you need to lock it. At this point, local variables can be stored within the thread via ThreadLocal. ThreadLocal trades space for time, and Synchronic trades time for space. 2. Release remove to prevent OOM generation.