Understanding Thread Pool in android

Posted by mcbeckel on Tue, 21 May 2019 02:59:35 +0200

1. What is thread pool

When we want to use a thread, we can create a thread, but if we want to use multiple threads, we need to create multiple threads. But threads are a kind of restricted system resources, which can not be generated indefinitely, and the creation and destruction of threads will produce corresponding overhead. If threads are created and destroyed frequently, the efficiency of the system will be affected. At this point we can use thread pools. Thread pool caches a certain number of threads so that threads can be reused. After the thread has finished the task, it will not destroy and continue to perform other tasks. Thread pooling avoids system overhead caused by frequent creation and destruction of threads.

2.ThreadPoolExecutor

Thread pool in android comes from Executor interface in java, which is implemented as ThreadPoolExecutor class. Let's first look at the construction of ThreadPool Executor:

public class ThreadPoolExecutor extends AbstractExecutorService {
    .....
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue);
 
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
 
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
 
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
        BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
    ...
}

There are seven parameters in total. First, we will analyze the meaning of each parameter.
int corePoolSize: Maximum number of core threads in the thread pool
When a thread pool creates a new thread, if the current number of threads is less than corePoolSize, a core thread will be created, and if the current number of threads is greater than corePoolSize, a non-core thread will be created. Core threads will always live in the thread pool by default, but if the allowCoreThreadTime Out property of ThreadPoolExecutor is true, the survival time of idle core threads will be determined by keepAliveTime, and the idle core threads will be terminated if the idle core threads exceed keepAliveTime.

int maximumPoolSize: Maximum total number of threads in this thread pool
Total threads = Number of core threads + Number of non-core threads

Long keep AliveTime: Time-out for non-core threads idle

TimeUnit unit: keepAliveTime unit, is an enumeration
NANOSECONDS: 1 microsecond = 1 microsecond / 1000
MICROSECONDS: 1 microsecond = 1 millisecond / 1000
MILLISECONDS: 1 millisecond = 1 second / 1000
SECONDS: seconds
MINUTES:
HOURS: Hours
DAYS: Heaven

BlockingQueue workQueue: Task queue for this thread pool
BlockingQueue has multiple types

  • Array BlockingQueue: You can limit the length of the queue. When you receive a task, if it does not reach the value of corePoolSize, the new thread (core thread) executes the task. If it does, the new thread (non-core thread) waits in the queue. If the queue is full, the new thread (non-core thread) executes the task. If the number of bus threads reaches the maximum umPoolSize, and the queue is full, errors occur. error

  • LinkedBlockingQueue: When this queue receives a task, if the current number of threads is less than the number of core threads, the new thread (core thread) processes the task; if the current number of threads equals the number of core threads, it enters the queue and waits. Since there is no maximum limit on this queue, that is, all tasks that exceed the number of core threads will be added to the queue, which also causes the setting of maximum PoolSize to fail, because the number of bus threads will never exceed that of core PoolSize.

  • DelayQueue: The elements in the queue must implement the Delayed interface, which means that the tasks you pass in must first implement the Delayed interface. When the queue receives a task, it first enters the queue, and only when the specified delay time is reached will the task be executed.

  • SynchronousQueue: When this queue receives a task, it will be submitted directly to the thread for processing without retaining it. What if all threads are working? Then create a new thread to handle the task! Therefore, in order to ensure that there is no error that < the number of threads reaches maximum PoolSize and no new threads can be created >, when using this type of queue, maximum PoolSize is generally specified as Integer.MAX_VALUE, i.e. infinite.

  • Priority Blocking Queue (infrequently used): Priority-based blocking queue (priority judgment is determined by the Compator object passed in by the constructor), but it should be noted that Priority Blocking Queue does not block data producers, but only consumers of data when there is no consumable data. Therefore, when using it, special attention should be paid to the fact that the speed of producer's production data must not be faster than that of consumer's consumption data. Otherwise, a long time will eventually exhaust all available heap memory space. When implementing Priority Blocking Queue, the internal control thread synchronization lock uses fair lock.

ThreadFactory threadFactory: Thread factory, which provides the ability to create new threads for thread pools.

Rejected Execution Handler handler: This exception is thrown when the thread pool is unable to perform a new task

3. Classification of thread pools

The four most common types of thread pools in Android are implemented by configuring ThreadPool Executor

  • CachedThreadPool
    Source code:
public static ExecutorService newCachedThreadPool(){
   return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
}

CachedThreadPool is a thread pool with variable number of threads. It has only non-core threads. The maximum number of threads is Integer.MAX_VALUE. If there are idle threads, the idle threads are reused. If there are no idle threads, new threads are created. The idle threads in the thread pool have a timeout of 60 seconds. Some programs reduce the frequent creation/destruction of threads and system overhead.
Trial methods:

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            SystemClock.sleep(1000);
        }
    };
    ExecutorService cacheThreadPool = Executors.newCachedThreadPool();
    cacheThreadPool.execute(runnable);
  • FixedThreadPool
    Source code:
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
}

Fixed ThreadPool is a thread pool with a fixed number of threads, only core threads and these core threads will not be recycled, which can control the maximum number of concurrent threads, and the excess threads will wait in the queue.
Trial methods:

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            SystemClock.sleep(1000);
        }
    };
    ExecutorService fixedThreadPool= Executors.newFixedThreadPool(4);
    fixedThreadPool.execute(runnable);
  • ScheduledThreadPool
    Source code:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
}

public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
}

Scheduled ThreadPool's core threads are fixed, non-core threads are unrestricted, and non-core threads are immediately recycled when idle. It mainly supports timing and periodic task execution.
Trial methods:

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            SystemClock.sleep(1000);
        }
    };
   ExecutorService scheduledThreadPool =Executors.newScheduledThreadPool(4);
    scheduledThreadPool .execute(runnable);
  • SingleThreadExecutor
    Source code:
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
}

SingleThreadExecutor has only one core thread, and all tasks are executed in the specified order, i.e. following the queue entry and exit rules.
Trial methods:

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            SystemClock.sleep(1000);
        }
    };
    ExecutorService singleThreadPool =Executors.newSingleThreadPool();
    singleThreadPool .execute(runnable);
Reference resources:

http://blog.csdn.net/lift_class/article/details/70216690

Topics: Android less Java