Analyzing Threads and Thread Pool in Android

  • 2021-12-13 09:30:52
  • OfStack

Directory Preface HandlerThreadIntentService Thread Pool Benefits ThreadPoolExecutor Thread Pool Classification FixedThreadPoolCachedThreadPoolScheduledThreadPoolSingleThreadExecutor

Preface

Because of too much content, it will be divided into two parts. Part 1 mainly talks about threads in Android and thread pools commonly used in Android. In Part 2, let's learn about the use and working principle of AsyncTask under 1.

HandlerThread

HandlerThread is a subclass of Thread, which is a kind of Thread that can use Handler, and its implementation is relatively simple. Let's look at its source code:


package android.os;

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }


      public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }


       protected void onLooperPrepared() {
    }



    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }



     public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }



       public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }





      public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }




     public int getThreadId() {
        return mTid;
    }
}

In order to let everyone see clearly, our source code 1 of the English notes killed, now it is very clear. In addition to constructing methods and externally providing several public methods, there is only one method left in the whole class, run (). From its implementation, it is no different from the ordinary Thread implementation. Time-consuming operations are performed in the run () method. However, the message queue is created internally in HandlerThread, and the run () method is an infinite loop method, so when we don't need HandlerThread, we can call quitSafely () or quit () to end the thread. This is more convenient.

IntentService

IntentService is a special Service, it is a subclass of Service, and it is an abstract class, so you must create a subclass to use Intent Service. Intent Service can be used to perform time-consuming tasks in the background. When the task is finished, it will end by itself, without the need to manually end it. There is a problem to pay attention to here. Intentservice has built-in threads, but it still belongs to Service, so its priority will be much higher than threads, so it is not easy to be killed by the system. Therefore, it is more appropriate to perform some tasks with higher priority. Look at its source code:


package android.app;

import android.annotation.WorkerThread;
import android.annotation.Nullable;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;



public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;



    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }



        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }




    public IntentService(String name) {
        super();
        mName = name;
    }




   public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }




    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }




      @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }




    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }




    public IBinder onBind(Intent intent) {
        return null;
    }




    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

This is very simple, and these methods are familiar to friends who often use Service. Let's look at the onCreate () method. Yes, IntentService encapsulates HandlerThread and Handler.

When we start IntentService is onCreate (), the method will be called and HandlerThread and ServiceHandler will be created. The onStartCommand () method calls the onStart () method. From the onStart () method, it can be seen that IntentService only sends a message through ServiceHandler, and this message will be processed in HandlerThread.

Look at this onStart () method and pass intent as a message to onHandleIntent, which is usually the data we pass in. And onHandleIntent is through this intent to distinguish specific background tasks.

Ok, how AsyncTask works. We will talk about it in the next chapter. Let's look at the thread pool.

I don't know if everyone has encountered this situation. When we are writing a project and encounter time-consuming operations, what should we do? Is it new Thread (). start? In this case, how many Thread are new in the whole project? This is obviously a waste of performance. After all, threads are also good resources. So is there a way to reuse threads? The answer is thread pool.

Benefits of thread pooling

1. Reuse the threads in the thread pool to avoid the performance overhead caused by the creation and destruction of threads.

2. It can effectively control the number of concurrent threads in the thread pool and avoid blocking caused by preempting resources among a large number of threads.

3. It can manage threads simply, and provide functions such as timing execution and loop execution at specified intervals.

ThreadPoolExecutor

The concept of thread pool in Android comes from Executor in java, Executor is an empty interface, and the real thread pool realizes ThreadPoolExecutor.


public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }

This paper briefly introduces the meaning of each parameter of ThreadPoolExcutor under 1

corePoolSize: The number of core threads in the thread pool. By default, core threads will survive at 1 in the thread pool, even if they are idle. When we set the allowCoreThreadTimeOut property in ThreadPoolExecutor to true, the idle core thread will be reclaimed if the time exceeds the time set by keepAliveTime while waiting for a new task.

maximumPoolSize: Set the maximum number of threads that can be accommodated in the maximum thread pool. When the number of threads in the thread pool reaches this number, new tasks will be blocked.

keepAliveTime: Number of idle non-core threads.

unit: Specifies the time unit for the keepAliveTime parameter.

workQueue: Task queue in thread pool.

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

Classification of thread pool

There are four common thread pools in Android, FixedThreadPool, CachedThreadPool, ScheduledThreadPool and SingleThreadExecutor.

FixedThreadPool

The FixedThreadPool thread pool is created by the new FixedThreadPool method of Executors. Its characteristic is that the number of threads in the thread pool is fixed. Even if threads are idle, they will not be recycled unless the thread pool is closed. When all threads are active, new tasks are queued for the threads to process. Note that FixedThreadPool has only core threads and no non-core threads.


public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                            0L, TimeUnit.MILLISECONDS,
                            new LinkedBlockingQueue<Runnable>(),
                            threadFactory);
}

CachedThreadPool

The CachedThreadPool thread pool is created via newCachedThreadPool of Executors. It is a thread pool with an unfixed number of threads. It has no core threads, only non-core threads. When all the threads in the thread pool are active, new threads will be created to handle new tasks. Otherwise, idle threads will be used to process new tasks. All threads in the thread pool have a timeout mechanism, which lasts for 60s. After this time, idle threads will be reclaimed. This thread pool is suitable for handling a large number of tasks that take less time. It must be said here that the task queue of CachedThreadPool is basically empty.


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

ScheduledThreadPool

The ScheduledThreadPool thread pool is created through newScheduledThreadPool of Executors. Its core threads are fixed, but the number of non-core threads is not fixed, and when non-core thread 1 is idle, it is immediately recycled. This thread is suitable for executing timed tasks and repetitive tasks with fixed periods.


public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }


public ScheduledThreadPoolExecutor(int corePoolSize,
                                       ThreadFactory threadFactory) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue(), threadFactory);
    }

SingleThreadExecutor

SingleThreadExecutor thread pool is created by newSingleThreadExecutor method of Executors. There is only one core thread and no non-core thread in this thread pool, which ensures that all tasks can be executed on the same thread and in sequence, so there is no need to consider the problem of thread synchronization.


public static ExecutorService newSingleThreadExecutor() {

        return new FinalizableDelegatedExecutorService

            (new ThreadPoolExecutor(1, 1,

                                    0L, TimeUnit.MILLISECONDS,

                                    new LinkedBlockingQueue<Runnable>()));

    }

The above is the analysis of Android Threads and Thread Pool details, more about Android Threads and Thread Pool information please pay attention to other related articles on this site!


Related articles: