Android multithreaded Programming thread Pool Learning chapter (i)

Source: Internet
Author: User

Android multithreaded Programming thread Pool Learning chapter (i) I. Preface

In Android application development, multi-threaded programming is widely used, and the application is more threadpoolexecutor,asynctask,intentservice,handlerthread,asynctaskloader, For a more detailed analysis of each implementation, a separate analysis will be made. The following chapters may involve knowledge of the thread pool, which is why this analysis uses the thread pool, how the thread pool is used, and how the thread pool works.

Second, Thread Pool base

A process represents a running program, and a running Android application is a process. From the aspect of the operating system, a thread is a child task that can be executed independently in a process. A process can have multiple threads, and a thread in the same process can share resources in a process. From the aspect of the JVM, a thread is a component in a process that is the smallest unit of execution of Java code.

In the Android app development process, if you need to handle asynchronous or concurrent tasks with a thread pool, using the thread pool can have the following benefits:
1, reduce resource consumption: the creation and destruction of threads need to consume resources, reusable threads can avoid excessive consumption of resources.
2, improve the response speed: When a task needs to be executed, you can begin to perform the task without recreating the thread.
3, improve the management of threads: excessive creation of threads will reduce the stability of the system, using the thread pool can be unified allocation, tuning and monitoring.

The principle of the Thread pool mode is to use the queue to treat the task to be cached, and to reuse a certain number of worker threads from the queue to remove the task to execute. Its essence is to use a limited amount of resources to handle unlimited tasks.

The core class of the thread pool pattern is threadpoolexecutor, which is the implementation class for the thread pool. Using executors, you can create three types of threadpoolexecutor classes, mainly the following three types:
(1) Fixedthreadpool
(2) Singlethreadexecutor
(3) Cachedthreadpool

Three, executor framework analysis

The executor interface provides a way to separate task submissions from the mechanics of how each task will run, including details, schedules, and so on, that are used by threads.

Executor framework mainly includes: Threadpoolexecutor, Scheduledthreadpoolexecutor, future interface, runable interface, callable interface and executors.

is a class diagram of the executor framework.

= = First the main thread creation task: = = The object of the task can be implemented by implementing the Runnable interface or the callable interface. And Runnable can be executors.callable (Runnable Runnable) or executors.callable (Runnable Runnable, Object result) method to convert the encapsulated object to callable.

= = followed by the execution of the task: = = There are two ways to perform a task, one is the Execut () method, the Runnable object that executes the commit, Executorservice.execute (Runnable Runnable), and the other is the Submit () method , you can execute the committed Runnable object, Executorservice.submit (Runnable Runnable), or the callable object that performs the commit, Executorservice.submit (callable Callable).

= = Cancel Task: = = You can choose to use Feturetask.cancel (Boolean flag) to cancel the task.

= = Close executorservice:== This will cause it to reject new tasks. There are two ways to turn off Executorservice. The shutdown () method allows previously committed tasks to be performed before terminating, while the Shutdownnow () method prevents the wait task from starting and attempts to stop the currently executing task. At the time of termination, the executor has no task to perform, no task is waiting to be executed, and the new task cannot be submitted.

Note: Unused executorservice should be closed to allow recycling of their resources.

The following methods turn off Executorservice in two phases. The first stage calls shutdown to reject the incoming task, and then calls Shutdownnow (if necessary) to cancel all the remaining tasks:

voidShutdownandawaittermination (Executorservice Pool) {pool.shutdown ();//Disable new tasks from being submitted   Try{//Wait a while for existing the tasks to terminate     if(!pool.awaittermination ( -, timeunit.seconds)) {Pool.shutdownnow ();//Cancel currently executing tasks       //Wait a while for the tasks to respond to being cancelled       if(!pool.awaittermination ( -, timeunit.seconds)) System.err.println ("Pool did not terminate"); }   }Catch(Interruptedexception IE) {//(re-) Cancel If current thread also interruptedPool.shutdownnow ();//Preserve interrupt statusThread.CurrentThread (). interrupt (); } }
Four, Threadpoolexecutor principle analysis

When a task is added to a thread pool, how does the thread pool work? The following principles are analyzed according to the source code:

 Public void Execute(Runnable command) {if(Command = =NULL)Throw NewNullPointerException ();intc = ctl.Get();if(Workercountof (c) < corepoolsize) {if(Addworker (Command,true))return; c = ctl.Get(); }//If the number of threads is greater than or equal to the number of base threads or thread creation fails, the current task is placed in the work queue.     if(IsRunning (c) && workqueue.offer (command)) {intRecheck = ctl.Get();if(! isrunning (Recheck) && Remove (command)) reject (command);Else if(Workercountof (recheck) = =0) Addworker (NULL,false); }//If the thread pool is not running or the task cannot be placed in the queue, and the current number of threads is less than the maximum allowable number of threads. A thread is created to perform the task.     Else if(!addworker (Command,false))//throws an Rejectexecutionexception exception. Reject (command);}

The following is the main processing flowchart for the thread pool:


As you can see, when a task is submitted,
* First, determine if the core thread pool is performing a task, and if there are threads that do not perform the task, a new core will be created to perform the task, otherwise it will go into the next process.
* If the queue for the storage task is not full, then the task is stored in the queue, and if the queue is full, it will go into the next process.
* Determine if there are non-core threads in the thread pool that are not working, and if not, create a new thread to perform the task and, if it is full, go to the next stage.
* When both the thread and queue are full, the rejectdeexecutionhandler is handled in four ways, as shown in:

The processing of the task is clear from the diagram above.

After about Threadpoolexecutor, let's say how to create a thread pool.

newunit, workQueue, threadFactory, defaultHandler);

1) corepoolsize (the basic size of the thread pool, or the size of the number of core threads): If a task is committed, the number of core threads in the thread pool is less than the base size value, or if the core thread is idle, a thread is created to perform the submitted task. It is not created when the number of threads equals the base size.
Note: = = when the Prestartallcorethreads () method in the thread pool is called, the thread pooling creates and starts all the basic threads in advance, the so-called core thread.

2) Maximumpoolsize (maximum number of thread pools): The maximum number of threads that the so-called thread pool can create, where the number contains both core and non-core threads. If the task in the queue is full and the number of threads is less than the maximum number of thread pools, the new thread class is created to perform the task.
= = = = = When the queue is unbounded, the maximum value of the set thread pool is invalid.

3) KeepAliveTime (duration of thread activity): When the worker thread of the thread pool is idle, the time to remain alive.
Usage scenarios: When too many tasks are submitted, you can set a large time value to fully increase the utilization of the thread.

4) Unit (Time unit of thread activity hold): You can select the appropriate time unit. such as days, hours, minutes, seconds, milliseconds, microseconds, 1 per thousand milliseconds, and nanoseconds.

5) WorkQueue (queue for storage tasks): The blocking queue that is used to hold the awaited task. This form of blocking queue is common in several ways:
Arrayblockingqueue: Bounded blocking queue based on array structure, sorted by FIFO principle.
Linkedblockingqueue: A blocking queue based on a linked list structure, sorted by FIFO principle.
Synchronousqueue: The blocking queue for the element is not stored.
Priorityblockingqueue: An infinite blocking queue with a priority.

6) Threadfactory (the factory used to create the thread): Creates a thread from the Factory mode.

7) DefaultHandler (processing mode of saturation policy): When the queue and thread pool are full, this state is saturated, and a strategy must be taken to handle new tasks that cannot be performed. There are four ways to handle saturation strategies:

    • AbortPolicy: Throws an exception directly.
    • Callerrunspolicy: Runs the task only with the caller's thread.
    • Discardoldestpolicy: Discards the most recent task in the queue and executes the current task.
    • Discardpolicy: Discards the task directly.
Five, Fixedthreadpool principle analysis

Fixedthreadpool is created by using the Newfixedthreadpool () method in executors.
This is the thread pool that creates a reusable number of fixed threads and runs them in a shared, unbounded queue. In this thread pool, there are only core threads, no non-core threads, and when the core thread is idle, the thread is not reclaimed and is recycled only when the thread pool is closed.

(1) If the number of threads running is less than corepoolsize, a new thread is created to perform the task and the task is added to the task queue when a task is too late to process the thread. When the number of tasks is less than the number of threads, the thread pool execution results as follows:

 Public Static void Main(string[] args) {Executorservice EService = Executors.newfixedthreadpool ( +); for(inti =0; I <2; i++) {Final intj = i; Eservice.execute (NewRunnable () {@Override                 Public void Run() {System.out.println (Thread.CurrentThread (). GetName () +" "+ j);        }            }); }    }

Operation Result:
Pool-1-thread-2 1
Pool-1-thread-1 0
Indicates that only two threads are created in the thread pool first.

(2) If the number of tasks is greater than the number of core threads, then when the thread finishes executing the task, the task is taken from the queue. The instance code is as follows:

 Public Static void Main(string[] args) {Executorservice EService = Executors.newfixedthreadpool (4); for(inti =0; I < -; i++) {Final intj = i; Eservice.execute (NewRunnable () {@Override                 Public void Run() {Try{Thread.Sleep ( -); }Catch(Interruptedexception e)                    {E.printstacktrace (); } System.out.println (Thread.CurrentThread (). GetName () +" ", M);        }            }); }    }

Operation Result:
Pool-1-thread-1 0
Pool-1-thread-4 3
Pool-1-thread-3 2
Pool-1-thread-2 1
Pool-1-thread-4 4
Pool-1-thread-3 5
Pool-1-thread-2 7
Pool-1-thread-1 6
Pool-1-thread-4 8
Pool-1-thread-3 9
Pool-1-thread-2 10
Pool-1-thread-1 11
Pool-1-thread-4 12
...
As you can see from the running results, threads in the thread pool are not created indefinitely, with a maximum size of corepoolsize.

Six, Singlethreadexecutor principle analysis

Singlethreadexecutor is created by using the Newsinglethreadexecutor method of executors, which runs the thread in a unbounded queue. There is only one core thread inside this thread pool, and there is no non-core thread. The Singlethreadexecutor source code is implemented as follows:

publicstaticnewSingleThreadExecutor(){    returnnew FinalizableDelegatedExecutorService        (new ThreadPoolExecutor(110L, TimeUnit.MILLISECONDS,         new LinkedBlockingQueue<Runnable>()));}

Where Corepoolsize and Maximumpoolsize are set to 1, others are the same as fixpoolthread.

(1) When the number of threads in the thread pool is less than corepoolsize, a new thread is created to perform the task.

(2) If the number of tasks is greater than the number of core threads, then when the thread finishes executing the task, it takes the task from the queue and executes in order. The instance code is as follows:

 Public Static void Main(string[] args) {Executorservice EService = Executors.newsinglethreadexecutor (); for(inti =0; I < -; i++) {Final intj = i; Eservice.execute (NewRunnable () {@Override                 Public void Run() {Try{Thread.Sleep ( -); }Catch(Interruptedexception e)                    {E.printstacktrace (); } System.out.println (Thread.CurrentThread (). GetName () +" "+ j);        }            }); }    }

Operation Result:
Pool-1-thread-1 0
Pool-1-thread-1 1
Pool-1-thread-1 2
Pool-1-thread-1 3
Pool-1-thread-1 4
Pool-1-thread-1 5
Pool-1-thread-1 6
Pool-1-thread-1 7
Pool-1-thread-1 8
Pool-1-thread-1 9
Pool-1-thread-1 10
Pool-1-thread-1 11
Pool-1-thread-1 12
Pool-1-thread-1 13
Pool-1-thread-1 14
Pool-1-thread-1 15
Pool-1-thread-1 16
Pool-1-thread-1 17
Pool-1-thread-1 18
Pool-1-thread-1 19
Pool-1-thread-1 20

As you can see from the running results, there is only one core thread in the thread pool, and the task is performed in a certain order.

Seven, Cachedthreadpool principle analysis

Cachedthreadpool is created using the Newcachedthreadpool () method in executors, which is a thread pool with an irregular number of threads, no core thread, only non-core threads, and a number of non-core threads with a value of integer.max_ VALUE.
The source code created by Cachedthreadpool is:

publicstaticnewCachedThreadPool(ThreadFactory threadFactory) {    returnnew ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>(),threadFactory);}

The KeepAliveTime is 60L, which indicates that the idle thread waits for a new task ID for the maximum time of 60s, and if it exceeds 60s, the thread terminates and is recycled. The queue used by Cachedthreadpool is Synchronousqueue, which is a unbounded queue.

(1) If a thread in a thread pool is processing a task less quickly than the commit task, the thread pools constantly create new threads to handle the task, so too many threads of creation run out of CPU and memory resources.
(2) When a thread in a thread pool is active, the line pool creates a new thread to handle the task that the main thread commits, and if there are idle threads, it takes advantage of the idle thread to process the task.
(3) Synchronousqueue is a blocking queue with no capacity. Each insert operation must wait for the corresponding removal of another thread, and vice versa. Cachedthreadpool uses Synchronousqueue to pass the task submitted by the main thread to the idle thread for execution.

Viii. Summary

After familiar with some knowledge of thread pool, we should be familiar with how to rationally configure thread pool, and how to choose the way of threading pools.

How to properly configure the thread pool requires analysis from several aspects of the task:

    • Nature of tasks: CPU-intensive, IO-intensive, and hybrid.
    • Priority of tasks: high, Medium, and low.
    • Time the task was executed: long, medium, and short.
    • task dependencies: Whether to rely on other system resources, such as database connections.

From the nature of the task, if it is a CPU-intensive task, then try to configure as few threads as possible, such as the thread pool of the thread that configures N+1 (n is the number of cores of the CPU). If it is an IO-intensive task, configure as many threads as possible, such as 2*n. For a mixed-type task, if it can be split, split it into a CPU-intensive task and an IO-intensive task, as long as the time difference between the two tasks is not too large, then the throughput performed after the decomposition will be higher than the throughput of the serial execution. If the execution time of these two tasks is too large, no decomposition is necessary. The number of CPUs for the current device can be obtained through the Runtime.getruntime (). Availableprocessors () method.

From the priority of the task, you can use the priority Team Priorityblockingqueue processing. High-priority tasks are processed first, but in a less-than-good situation, a low-priority task may not be processed.

Depending on the execution time, a thread pool of different sizes can be handed over, or a priority queue can be used to execute a task with a short execution time.

From the dependency, this main introduction of the database connection, because the thread will need to wait for the database to return the results, the longer the waiting time, the longer the CPU idle time, then the number of threads should be set larger, so as to better utilize the CPU.

The three-way thread pool, fixedthreadpool, is suitable for resource-intensive tasks, singlethreadexecutor suitable for sequential tasks, cachedthreadpool suitable for performing a large amount of time-consuming tasks.

Resources:
The art of Java concurrent programming
The core technology of Java multithreaded programming

Thread pool for Android multithreaded programming (i)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.