Android Thread management (III)-internal principle, sleep and awakening of Thread class, androidthread
Thread communication, ActivityThread, and Thread classes are the key to understanding Android Thread management.
As the basic unit of CPU scheduling resources, threads play a very important and fundamental role in Android and other operating systems for embedded devices. This section mainly analyzes the following three aspects:
Iii. Internal principles of the Thread class, sleep and awakening the Internal principles of the 3.1 Thread class
A Thread is the basic unit of CPU resource scheduling and belongs to the abstract category. Java completes Thread management through the Thread class. The essence of the Thread class is actually "executable code", which implements the Runnable interface, and the only method of the Runnable interface is run ().
public class Thread implements Runnable { ……}
public interface Runnable { /** * Starts executing the active part of the class' code. This method is * called when a thread is started that has been created with a class which * implements {@code Runnable}. */ public void run();}
From the annotations, we can see that the start () method to call the Thread is the run () method that indirectly calls the Runnable interface.
public synchronized void start() { checkNotStarted(); hasBeenStarted = true; VMThread.create(this, stackSize);}
VMThread in start () method. create (this, stackSize) is the place where the CPU Thread is actually created. In other words, only the Thread after start () is called to create the CPU Thread, the newly created thread runs the run () method of the Runnable interface.
3.2 thread sleep and Wakeup
Thread communication, synchronization, and collaboration are common problems in multi-thread programming. Thread collaboration is usually implemented through thread sleep and wakeup. Thread sleep is implemented by waiting for the lock (monitor) of an object (wait () method ), when other threads call the notify () method of the object, the thread is awakened. This object implements data transmission between threads, and multiple threads implement collaboration through this object.
A typical example of thread collaboration is the "producer-consumer mode" in the Java design mode. The producer constantly writes data to the buffer, and the consumer extracts data from the buffer for consumption. In implementation, the producer and consumer inherit the Thread respectively, and the buffer uses the priority queue PriorityQueue to simulate. The premise for the producer to put data into the buffer zone is that there is free space in the buffer zone. The premise for the consumer to retrieve data from the buffer zone is that there is data in the buffer zone. Therefore, this involves the collaboration between the producer thread and the consumer thread. Below is a brief description of the Code.
Import java. util. priorityQueue; public class TestWait {private int size = 5; private PriorityQueue <Integer> queue = new PriorityQueue <Integer> (size); public static void main (String [] args) {TestWait test = new TestWait (); Producer producer = test. new Producer (); Consumer consumer = test. new Consumer (); producer. start (); consumer. start ();} class Consumer extends Thread {@ Override public void run () {while (true) {synchronized (queue) {while (queue. size () = 0) {try {System. out. println ("queue empty, waiting for Data"); queue. wait ();} catch (InterruptedException e) {e. printStackTrace (); queue. notify () ;}} queue. poll (); // each time the first element of the queue is removed. using Y (); System. out. println ("remove an element from the queue, remaining queue" + queue. size () + "element") ;}}} class Producer extends Thread {@ Override public void run () {while (true) {synchronized (queue) {while (queue. size () = size) {try {System. out. println ("queue full, waiting for free space"); queue. wait ();} catch (InterruptedException e) {e. printStackTrace (); queue. notify () ;}} queue. offer (1); // insert an element queue each time. using Y (); System. out. println ("insert an element into the queue, the remaining queue space:" + (size-queue. size ()));}}}}}
This code is described in many cases.Producer-consumer modelWhere, the Producer thread starts first, and the synchronized keyword enables it to obtain the queue lock, while other threads are waiting. The initial queue is empty and data is written to the Buffer queue by offer. The notify () method wakes up the thread waiting for the Buffer queue (this is the consumer thread, however, this thread does not immediately obtain the queue lock. Only when the producer thread continuously writes data to the queue until the queue. size () = size, the Buffer Queue is full, and the producer thread calls the wait () method to enter the waiting state. At this time, the consumer thread is in the wake-up state and obtains the queue lock, and uses the poll () method to consume the data in the buffer. Similarly, although the producer thread is awakened by calling the Y () method, however, it cannot immediately obtain the queue lock, and only when the consumer thread continuously consumes data until the queue. size () = 0, the consumer thread calls the wait () method to enter the waiting state, the producer thread obtains the queue lock again, and loops through the above process to complete the collaboration between the producer thread and the consumer thread.
In Android SystemServer, multiple threads are used for collaboration. For example, in main () of WindowManagerService, BlockingRunnable started by runWithScissors () is used for collaboration with the thread of SystemServer. WindowManagerService Source Code address can refer to: https://github.com/android/platform_frameworks_base/blob/master/services/core/java/com/android/server/wm/WindowManagerService.java
3.3 thread interruption
In Java, the "interrupt" thread is implemented through the interrupt () method. The quotation marks are added because interrupt () does not interrupt the running thread, but only sends an interrupt request to the thread, the specific behavior depends on the thread status, which is described as follows:
Posts an interrupt request to this Thread. The behavior depends on the state of this Thread:
- Threads blocked in one of Object's wait () methods or one of Thread's join () or sleep () methods will be woken up, their interrupt status will be cleared, and they receive an InterruptedException.
- Threads blocked in an I/O operation of an java. nio. channels. interruptibleChannel will have their interrupt status set and receive an java. nio. channels. closedByInterruptException. also, the channel will be closed.
- Threads blocked in a java. nio. channels. Selector will have their interrupt status set and return immediately. They don't receive an exception in this case.
Translation:
- If the thread is in the blocking status, that is, the thread is Object. wait (), Thread. join () or Thread. sleep () Blocking: Call the interrupt () method to receive an InterruptedException exception, clear the interruption status, and end the blocking status;
- If the thread is performing I/O operations (java. nio. channels. interruptibleChannel) is blocked, the thread will receive java. nio. channels. closedByInterruptException exception. The channel is closed and the blocking status ends;
- If the thread is blocked in java. nio. channels. Selector, the interruption status will be set and returned, and no exception will be thrown.
public void interrupt() { // Interrupt this thread before running actions so that other // threads that observe the interrupt as a result of an action // will see that this thread is in the interrupted state. VMThread vmt = this.vmThread; if (vmt != null) { vmt.interrupt(); } synchronized (interruptActions) { for (int i = interruptActions.size() - 1; i >= 0; i--) { interruptActions.get(i).run(); } }}
3.4 join () and sleep () Methods
The join () method can also be understood as a way of collaboration between threads. When two threads need to be executed sequentially, calling the join () method of the first thread can block the thread, it is still implemented through the wait () method.
/** * Blocks the current Thread (<code>Thread.currentThread()</code>) until * the receiver finishes its execution and dies. * * @throws InterruptedException if <code>interrupt()</code> was called for * the receiver while it was in the <code>join()</code> call * @see Object#notifyAll * @see java.lang.ThreadDeath */public final void join() throws InterruptedException { VMThread t = vmThread; if (t == null) { return; } synchronized (t) { while (isAlive()) { t.wait(); } }}
In addition, the join () method with time parameters exits after the specified time is exceeded. Similarly, it is implemented through the wait () method with time parameters.
public final void join(long millis) throws InterruptedException{}public final void join(long millis, int nanos) throws InterruptedException {}
The similarities between sleep () and wait () are that they are all blocked by waiting for the thread. The difference is that sleep () waits for time and wait () waits for the lock of the object.
public static void sleep(long time) throws InterruptedException { Thread.sleep(time, 0);}
public static void sleep(long millis, int nanos) throws InterruptedException { VMThread.sleep(millis, nanos);}
3.5 CountDownLatch
CountDownLatch is located in java. util. concurrent. CountDownLatch to implement the countdown counter latch. When the count is reduced to 0, a specific event is triggered. Some main threads need to wait until the application of the sub-thread is very practical. Take a piece of code in Google's zxing open-source library as an example:
final class DecodeThread extends Thread { …… private final CountDownLatch handlerInitLatch; DecodeThread(CaptureActivity activity, Collection<BarcodeFormat> decodeFormats, Map<DecodeHintType,?> baseHints, String characterSet, ResultPointCallback resultPointCallback) { this.activity = activity; handlerInitLatch = new CountDownLatch(1); …… } Handler getHandler() { try { handlerInitLatch.await(); } catch (InterruptedException ie) { // continue? } return handler; } @Override public void run() { Looper.prepare(); handler = new DecodeHandler(activity, hints); handlerInitLatch.countDown(); Looper.loop(); }}
In the preceding example, the CountDownLatch object is initialized in the DecodeThread constructor and the initialization parameter 1 is input. Second, the CountDownLatch object countDown () method is called in the run () method, which ensures that the handler is not null when the external instance obtains the handler through the getHandler () method.