Android multi-threaded implementation

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/Kennethdroid/article/details/90179697

A good programmer must have two capabilities: learning ability, time management skills

The original article first appeared in the public micro-channel number "byte floating"

Android multi-threaded implementation

Generally speaking, an application has at least one process, and a process has at least one thread.

A thread is the basic unit of CPU scheduling, process is the basic unit of allocation of system resources.

Process exclusive memory resources, a process can be seen as a JVM, after a process crashes, will not have an impact on other processes in general in protected mode.
The same process in the thread shared memory resources, has led to a dead thread throughout the process dies.

Android provides four common multi-threaded implementation:

  • AsyncTask
  • Asynchronous messaging
  • IntentService
  • ThreadPoolExcutor

AsyncTask

Our old friend AsyncTask class, which is packaged thread pool, the UI thread is extremely easy to operate.

A look at one, three generic parameters of AsyncTask:

public abstract class AsyncTask<Params, Progress, Result>

  • params, Passed parameter type , i.e., the doInBackground () method parameter type;
  • Progress, The process returns to asynchronous tasks in the task execution schedule type , i.e. publishProgress () and onProgressUpdate () method passing type parameters;
  • Result, Asynchronous tasks End result type of return type, i.e. the doInBackground () method returns the value.

Four callback method:

  • onPreExecute()In the main thread of execution, to do some preparation work.
  • doInBackground()In the thread pool, which is an abstract method, this method can be called in publishProgress()the update task progress.
  • onProgressUpdate()Executed in the main thread, in publishProgress () after the call is called back to show the progress of the task.
  • onPostExecute()Executed in the main thread, after the end of asynchronous tasks, this callback method, processing returns the result.

Note :

  • When AsyncTask task is canceled, the callback onCanceled (obj), this time onPostExecute (), will not be called, cancel AsyncTask in () method is not really going to cancel the task, just set the task to be canceled and the need to doInBackground ( ) and () terminates the task is determined by isCancelled.
  • AsyncTask must create an instance in the main thread, execute () method must be called in the main thread.
  • Each instance can only be executed once AsyncTask execute (), repeatedly being given, To perform many times, you need to create multiple instances.
  • After Android 3.0, AsyncTask object defaults multitasking is serial execution, namely mAsyncTask.execute (), then concurrent execution requires the use of executeOnExecutor ().
  • AsyncTask using a thread pool mechanism and asynchronous messaging (based on ThreadPoolExecutor and Handler). Android 2.3 before, AsyncTask thread pool capacity is 128, only five global thread pool worker threads, if used AsyncTask object to execute multiple concurrent asynchronous tasks, then the same time can be up to five threads running at the same time, other threads will be blocked . After 3.0 Android Google has been adjusted, new interfaces executeOnExecutor (), allows custom thread pool (then the kernel threads, and thread capacity can be customized), and provides SERIAL_EXECUTOR and THREAD_POOL_EXECUTOR predefined thread pool. Later, Google has made some adjustments (everything is not perfect), the capacity and the number of CPU core thread pool linked, such as the current version of the SDK 25, the number of kernel threads predefined least two, at most four, thread pool size range of 5 to 9. Changes are as follows:
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE_SECONDS = 30;

Asynchronous messaging

Asynchronous message mechanism of the three main characters: Handler, Message and Looper.
Looper is responsible for creating MessageQueue news column, and then enter an infinite for loop, continue to take the message from the message queue, if the message queue is empty, the current thread is blocked, Handler is responsible for sending messages to the message queue.

Looper

Looper has two important ways: prepare () and loop ().

  • prepare (), Looper with the current thread binding, a thread can be only one instance of Looper and a MessageQueue instance.
public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(true)); 保证 Looper 对象在当前线程唯一
}

// Looper 的构造方法
private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mRun = true;
        mThread = Thread.currentThread();
}
  • Loop, for entering an endless loop, constantly taking messages from the message queue and the message to dispatchMessage method to deal with the target property.
public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();


        // 无限循环体,有没有想过在 UI 线程里,有这样一个死循环,为什么界面没卡死??
        // 答案最后揭晓。
        for (;;) { 
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            msg.target.dispatchMessage(msg);

            msg.recycle();
        }
}

Handler

Handler is responsible for sending a message to the message queue.
In the Activity we can direct new Handler, it is because in the startup code Activity, it has been called Looper.prepare () and Looper.loop () method in the current UI thread.

new Handler must be created Looper objects and message queues in the current thread (child thread) in the sub-thread code is as follows

    //在子线程中

    Looper.prepare();

    handler = new Handler() {

	    public void handleMessage(Message msg) {
		    //处理消息
	    };
    };

    Looper.loop();   

After that, you can take this Handler objects in other threads, to this sub-thread's message queue in the message.

HandlerThread

HandlerThread can be considered to create an asynchronous message processing mechanisms in the sub-thread simplified version, HandlerThread objects automatically help us to create Looper objects and messages in the work queue thread.

Instructions:

mHandlerThread = new HandlerThread("MyHandlerThread");
mHandlerThread.start();

mHandler = new Handler(mHandlerThread.getLooper()){
   
    @Override
    public void handleMessage(Message msg) {
        //处理消息
    }
};

Then you can use a Handler object to the worker thread's message queue in the message.

Look at the source code fragment:

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

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

    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;
    }
}

Note : handler initialization in the UI thread, looper thread execution in a child, we must wait after mLooper created before calling getLooper, the source code is to solve the problem of synchronizing two threads through the wait and notify.

IntentService

IntentService can be seen as Service and HandlerThread fit. It inherits from the Service, and can handle asynchronous requests, it has an internal WorkerThread to handle asynchronous tasks, when the task is finished, IntentService stops automatically.

If you start repeatedly IntentService it? See HandlerThread, you should think many times to start IntentService, multiple asynchronous task is to put the task queue inside, and then executed serially in onHandlerIntent callback method, automatically ends after the implementation.

The following simple parsing of the source code, IntentService Source:

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 方法在工作线程中执行,执行完调用 stopSelf() 结束服务。
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }

    /**
     * enabled == true 时,如果任务没有执行完,当前进程就死掉了,那么系统就会令当前进程重启。
     * 任务会被重新执行。
     */
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }
    @Override
    public void onCreate() {
        super.onCreate();

        // 上面已经讲过,HandlerThread 对象 start 之后,会在工作线程里创建消息队列 和 Looper 对象。
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
			
        mServiceLooper = thread.getLooper();
        // 获得 Looper 对象初始化 Handler 对象。
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        // IntentService 每次启动都会往工作线程消息队列中添加消息,不会创建新的线程。
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    // 官方建议 IntentService onStartCommand 方法不应该被重写,注意该方法会调用 onStart 。
    @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();
    }
    /**
     * 不建议通过 bind 启动 IntentService ,如果通过 bind 启动 IntentService ,那么 onHandlerIntent 方法不会被回调。Activity 与 IntentService 之间的通信一般采用广播的方式。
     */
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }
    /**
     * 子类必须要实现,执行具体的异步任务逻辑,由 IntentService 自动回调。
     */
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

IntentService source code is easy to understand, you can also package their IntentService on their own scenarios.

Scenes

  • Under normal circumstances, start IntentService, the task is completed, the service stops;
  • Before asynchronous task is complete, stop IntentService, the service is stopped, but the task will be executed, is completed, the end of the worker;
  • Repeatedly start IntentService, once the task is executed serially, after the execution, the service stops;
  • Repeatedly start IntentService, before the end of the implementation of all tasks, stop IntentService, stop the service, in addition to the currently executing task, follow-up tasks will not be executed;

ThreadPoolExcutor

Pictures from Jakob Jenkov blog

ThreadPool

Used to manage a set of worker threads, tasks, task queue (BlockingQueue) held in idle threads waiting to be executed in the thread pool.

Common constructor:

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
    int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue
);

  1. corePoolSize core thread pool size for the minimum number of threads maintained by the thread pool. corePoolSize initial value is 0, when a new task is added to the task queue, a new thread is created, this time even if there is a free thread pool thread, as long as the current number of threads less than corePoolSize, then the new thread is still being created.
  2. The maximum number of threads in the thread pool maintained maximumPoolSize.
  3. Survival time in the absence of new tasks come keepAliveTime idle threads.
  4. unit parameters of time unit keepAliveTime.
  5. workQueue task queue, it must be BlockingQueue.

Simple to use

Creating ThreadFactory, of course, you can also customize.
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };
Creating ThreadPoolExecutor.
// 根据 CPU 核心数确定线程池容量。
public static final int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors(); 

mThreadPoolExecutor = new ThreadPoolExecutor(
        NUMBER_OF_CORES * 2, 
        NUMBER_OF_CORES * 2 + 1,
        60L,
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<Runnable>(),
        backgroundPriorityThreadFactory
);
carried out
mThreadPoolExecutor.execute(new Runnable() { 
    
    @Override  
    public void run() {  
         //do something  
    } 

});

Future future = mThreadPoolExecutor.submit(new Runnable() { 
    
    @Override  
    public void run() {  
         //do something  
    } 

});

//任务可取消
future.cancel(true);

Future<Integer> futureInt = mThreadPoolExecutor.submit(new Callable<Integer>() {
    @override
    public Integer call() throws Exception {
        return 0;
    }

});

//获取执行结果
futureInt.get();

FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>(){
    @override
    public Integer call() throws Exception {
        return 0;
    }    

});

mThreadPoolExecutor.submit(task);
task.get();

Contacts and exchanges

Micro-channel public number of
My public number
individual micro letter
My WeChat

Guess you like

Origin blog.csdn.net/Kennethdroid/article/details/90179697