Objective
For mobile developers, "putting time-consuming tasks into child threads to ensure the fluency of UI threads" is the first rule of threading programming, but this iron is often the main cause of the slow flow of UI threads. While we are urging ourselves to use more threads, we need to remind ourselves of how to avoid threading out of control.
One of the complex reasons for multithreaded programming is its parallel characteristics, the way the human brain works more in line with the characteristics of the single threaded serial. One subsequent task is the most comfortable state of the brain, and frequent switching between tasks creates a system anomaly such as "headaches". The multitasking of the human brain and the diversity of the multitasking performance of the computer make it easy to err when designing parallel business logic.
Another complication is the side effects of threads, including, but not limited to: Multithreading data security, deadlock, memory consumption, object lifecycle management, and the UI of the cotton. Each new thread is like a pebble thrown into the lake, creating ripples in the distance you overlook.
It is the main way for us to perceive the world with the abstraction of things. As one of the "citizens" of the operating system world, the thread is how to get the CPU and memory resources, and how to achieve maximum benefit from other "citizens"? Take these entities and behaviors like the brain, like the operating system to open the "God perspective" to correctly control the thread of this powerful beast.
Process priority (processes Priority)
Thread boarding in the process, the thread's lifecycle is directly affected by the process, and the survival of the process is directly related to its priority. When dealing with process priorities, most people intuitively know that the foreground process (foreground process) priority is higher than the background processes (Background). But this kind of rough partition can't satisfy the demand of the operating system high precision dispatch. Whether Android or iOS, the system is further refined for the foreground,background process.
Foreground Process
Foreground generally means that the user's eyes are visible, but not necessarily active
. In the Android world, when an activity is in the foreground, if a user's event can be collected, input
it can be judged active
that if one of them pops up, it Dialog
becomes a Dialog
new active
entity, directly facing the user. Partially obscured activity
, although still visible, the state becomes inactive
. It's not the right distinction visible
and active
It's a mistake many novice programmers make.
Background Process
The background process also has a finer division. The so-called background can be understood as invisible (invisible). For invisible tasks, Android also has a distinction of importance. An important background task is defined as Service
if a process contains Service
(called a service process), it is differentiated by the system in "importance" and its priority is naturally higher than Service
the process not contained (called background Process), and finally there is a class of empty processes (Empty). At the beginning of the Empty process, it is difficult to understand how a process can be necessary if nothing is done. In fact, empty process is not empty, there are a lot of memory footprint.
In the world of iOS, Memory
Clean Memory
It is divided into and Dirty Memory
, Clean Memory
is the app boot is loaded into memory after the original part of the memory, usually including the initial stack, heap, text, data
and so segment,Dirty Memory
is due to the user's operation changed that part of the memory, that is, the app's state value. The system in the presence of low Memory warning will first clear out the dirty Memory, for users, the operation of the progress of all lost, even click the app icon again, it is all from the beginning. However, because it has Clean Memory
not been purged, the IO loss from the retrieval of the app data from the disk has been avoided and the startup will be faster. This is why many people feel that the app is slow to open after the phone restarts.
The empty process in the Android World also holds app-related Clean Memory
, and this part of the memory helps to boost the startup speed of apps. It is obvious that the empty process has the lowest priority.
To sum up, we can prioritize the process of the Android world into the following categories:
The priority of the process is divided into five categories from highest to lowest, the further down, the more likely to be killed by the system when the memory is tense. In short, the more easily the user perceives the process, the higher the priority must be.
Thread scheduling (Threads scheduling)
The Android system is based on a streamlined Linux kernel, and its thread scheduling is influenced by many factors, such as time slice rotation and priority control. Many beginners will assume that the time slice assigned to a thread is determined by its priority compared to other thread priorities, which is not entirely true.
The strategy used by the scheduler of the Linux system time slice
when it is allocated CFS(completely fair scheduler)
. This strategy will not only refer to the priority level of a single thread, it also tracks the number of times each thread has been fetched, and if the high-priority thread has been executing for a time slice
long time, but the low-priority thread has been waiting, the subsequent system will guarantee that the lower-priority thread will get more CPU time. Obviously, with this scheduling strategy, high priority threads do not necessarily time slice
have an absolute advantage, so the concept of Android on-line scheduling cgroups
cgroups
can better highlight the importance of some threads, making it easier for higher priority threads to get more time slice
.
Android divides threads into multiple group
categories, two of which are group
especially important. One is default group
that the UI threads fall into this category. The other is background group
that the worker thread should belong to the class where 。background group
all threads add up to only 5~10%, and all the time slice
rest are allocated default group
, so the design clearly guarantees the fluency of UI threads in drawing the UI.
There's a lot of people. The Android system is not as fluent as iOS because the UI thread's priority is consistent with the normal worker thread. This is actually a misunderstanding, and Android designers actually provide background group
the concept of reducing the CPU consumption of working threads, but unlike iOS, Android developers need to explicitly attribute worker threads background group
.
New Thread (New Runnable () {
@Override public
void Run () {
process.setthreadpriority (process.thread_ Priority_background);
}
). Start ();
So when we decide to le a thread to perform a task, we first need to ask ourselves whether the task is important at the time of completion to scramble for CPU resources with the UI thread. If not, lower the thread priority to attribute it background group
to, and if so, need a further profile to see if this thread is causing the UI thread's cotton.
Although the Android system is based on a thread based unit on task scheduling, setting a single thread
priority can also change the control groups
distribution that it belongs to, thereby affecting CPU time slice
the allocation. But the process's attribute changes also affect the scheduling of threads, and when an app goes backstage, the entire process that the app belongs to will go in to background group
make sure that the foreground
new process that the user sees can get as much CPU resources as possible. With ADB, you can view the current scheduling policies for different processes.
When your app is switched back to the foreground by the user, the thread that belongs to the process will return to the original group
. In the process of these users switching frequently, thread
the priority will not change, but the system in time slice
the distribution is constantly adjusted.
Do you really need a new thread?
The thread is not a boost to app performance, it solves the UI cotton balm. Each new thread consumes at least 64KB of memory, and the system can incur additional overhead between different threads switch context
. If you open a new thread at will, it's easy to find dozens of threads running at a time at some point in the app run, as the business expands. The result is the original want to solve the UI fluency, but instead led to the occasional uncontrolled cotton.
Mobile-end app Le threads are generally designed to keep the UI fluent and increase the responsiveness of app user operations. But is it necessary to put the task in the worker thread first to understand where the bottleneck is, I/O,GPU or CPU? The appearance of the UI cotton is not necessarily a time-consuming calculation of the UI thread, possibly for other reasons, such as the layout level too deep.
Try to reuse an existing worker thread (using a thread pool) to avoid a large number of concurrently active threads, such as setting the maximum number of concurrent HTTP requests. Or put the task into a serial queue (handlerthread) sequentially, the worker thread task queue is appropriate to handle a large number of time-consuming tasks, avoiding the occurrence of a single task blocking the entire queue.
What position do you use to make a thread?
new Thread()
This is the simplest way to do the Android system, and can only be applied to the simplest scenarios, but the simple benefits are accompanied by a lot of pitfalls.
New Thread (New Runnable () {
@Override public
void Run () {
}
}). Start ();
This approach simply started a new thread, without the concept of a task, unable to do state management. After start, the code in run is bound to be executed in the end and cannot be canceled in the middle.
Runnable as an anonymous inner class also holds a reference to the external class, which persists until the thread exits, preventing the external class object from being reclaimed by GC and causing a memory leak over time.
Without a thread-switching interface, you need to write additional thread-switching code to pass the processing results to the UI thread.
If you start from a UI thread, the thread priority defaults to, Default
and is equal to, the default cgroup
UI thread competing for CPU resources. This is especially important to remember in scenarios where the UI performance requirements are high
Process.setthreadpriority (Process.thread_priority_background);
Although background group
the thread in the total can only win 5~10% CPU resources, but this for the vast majority of the background task processing is more than enough, 1ms and 10ms for users, are fast to imperceptible, so we generally prefer to background group
perform the work thread task.
Asynctask
A typical asynctask implementation is as follows:
public class Myasynctask extends Asynctask {
@Override
protected Object doinbackground (object[] params) {
return null;
}
@Override
protected void OnPreExecute () {
super.onpreexecute ();
}
@Override
protected void OnPostExecute (Object o) {
super.onpostexecute (o);
}
}
Thread()
In contrast to the use, there are several more API callbacks to strictly standardize the interaction between the worker thread and the UI thread. Most of our business scenarios are almost consistent with this specification, such as going to disk to read pictures, scaling processing needs to be done at the worker thread, and finally drawing to a ImageView
control that needs to switch to the UI thread.
Several of the asynctask callbacks give us the opportunity to interrupt the task and be more flexible in the management of the task State Thread()
. It is noteworthy that the Asynctask cancel()
method does not terminate the execution of the task, and the developer needs to check cancel
the status value to determine whether to abort the task.
Asynctask also has an implicit problem of holding an external class object reference, requiring special attention to prevent accidental memory leaks.
Asynctask because the serial and parallel execution behavior in different system versions is inconsistent, is criticized by many developers, this is indeed a mishap, most of the multi-threaded scenarios need to be clear whether the task is serial or parallel.
Thread priority is a background
minimal impact on the execution of the UI thread.
Handlerthread
In the need for more granular control of multitasking, thread switching more frequently under the scene, Thread()
and AsyncTask
will appear powerless. Handlerthread is capable of these needs and even more.
Handlerthread will Handler
,,, Thread
Looper
MessageQueue
combine several concepts. Handler is the external interface of the thread, all new message
or runnable
through handler post
to the worker thread. Looper
MessageQueue
switch to the worker thread to execute the new task when it is fetched. Different post
methods allow us to control the task carefully, when it is executed, and the order of execution can be controlled. The biggest advantage of Handlerthread is MessageQueue
that it introduces concepts and can be used for multitasking queue management.
There is only one thread behind the Handlerthread, so the task is serially executed. The serial phase is more secure for parallelism, and there is no multithreading security problem between the tasks.
The threads generated by Handlerthread will remain alive, and Looper will continue to check in the thread MessageQueue
. This is different from the fact that Thread(),AsyncTask
the reuse of thread instances avoids the frequent rebuilding and destruction of threads-related objects.
HandlerThread
Thread(),AsyncTask
more code than needed, but better performance in practicality, flexibility, and security.
Threadpoolexecutor
Thread(),AsyncTask
A scenario suitable for dealing with a single task, handlerthread a scenario that is suitable for serial processing of multitasking. Threadpoolexecutor is a better choice when multitasking is needed in parallel.
public static Executor Thread_pool_executor
= new Threadpoolexecutor (core_pool_size, Maximum_pool_size, Keep_ ALIVE,
timeunit.seconds, Spoolworkqueue, sthreadfactory);
Thread pooling avoids the frequent creation and destruction of threads, and obviously performance is better, but the characteristics of thread pool concurrency are often the source of difficult illnesses, and the beginning of code demotion and runaway. Multithreading parallel to the resulting bug is often the occasional, inconvenient debugging, once the emergence will consume a lot of development energy.
ThreadPool has more flexibility than handlerthread in multitasking, but it also brings greater complexity and uncertainty.
Intentservice
I have to say that Android is very granular in API design, and the same work can be done through a variety of different classes. It's IntentService
another way to open a working thread, and you can tell by name the attributes that this worker thread will carry service
. and AsyncTask
different, no interaction with the UI thread, and unlike Handlerthread, the worker thread will always survive. Intentservice behind there is actually a handlerthread to serial processing Message Queue
, from the Intentservice onCreate
method can be seen:
@Override public
void OnCreate () {
//Todo:it would is nice to have the option to hold a partial wakelock
/D Uring processing, and to have a static startservice (context, Intent)
//How that would launch the service & Han D off a wakelock.
Super.oncreate ();
Handlerthread thread = new Handlerthread ("intentservice[" + Mname + "]");
Thread.Start ();
Mservicelooper = Thread.getlooper ();
Mservicehandler = new Servicehandler (mservicelooper);
}
Only after all of the Message
processing has finished, the worker thread will automatically end. So you can think IntentService
of it as a combination of what you want to do with Service
HandlerThread
UI-independent tasks in a worker thread.
Summarize
The android thread is a variety of ways, but ultimately it is mapped to Linux under the Pthread, the business design or can not take off and thread-related basic concept category: The sequence of threads, scheduling strategy, lifecycle, serial or parallel, synchronous or asynchronous and so on. Understand the various types of API thread behavior characteristics, in the design of specific business threading model natural Familiar, threading model design to have the entire app perspective breadth, avoid each business module play each. The above is the entire content of this article, I hope that the development of Android can help you, if there are questions to welcome comments to discuss.