前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >About ExecutorService(3),我所认识的AsyncTask

About ExecutorService(3),我所认识的AsyncTask

作者头像
小鄧子
发布2018-08-20 15:08:05
4410
发布2018-08-20 15:08:05
举报
文章被收录于专栏:小鄧子的技术博客专栏

打开电脑的时候已经深夜十二点多了,周末两天过的实在憋屈,小伙伴喊我去打球,因为脚趾的伤至少还要数周才能痊愈,于是当了一天的啦啦队,第二天果断没再去。。。

这一篇主要跟大家聊一聊,我所认识的AT。

提到AT,童鞋们一定首先想到的异步,其次,还可能引申出其他名词,比如,串行,并发,并行。很多人认为并发和并行是一码事,下面我就说一说,我对这个四种模式的理解。

异步:异步和同步是是相对的,同步就是执行完一个再执行另一个,需要等待。异步就是彼此相对独立,再等待某件事的过程中继续做自己的事,不需要等待这一件事完成后再去做,举一个经典的不能在经典的例子,我的舍友花花同学的大金表坏了,让我去修,我到了商场,把手表递给修表师傅,修表这个时间段我可以逛商场,只需修完通知我就行了,我们两个就是彼此相互独立的。小结一下,可以说,异步是一个目的,更强调结果。而多线程是实现异步的一种方式。主线程不需要同步等待子线程的完成,从而可以干其他事。实现异步可以采用多线程技术,也可以交给另外的进程来处理。

并发:是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。其中两种并发关系分别是同步和互斥。举个例子说明一下,我的舍友花花比我起床早,去厕所洗漱,因为厕所只能容纳一个人,我起床后眼看要迟到了,于是就把刷一半牙的花花揪了出来,那么,我俩都满足由起床到洗漱完毕之间,并且是属于互斥关系的并发。

串行:跟同步相似,意思就是在一个时间片上只允许一个任务在进行,多个任务的执行,后一个任务必须等待前一个任务执行完毕才能工作,跟单核CPU一个时间片内只能执行一个任务类似。举个例子,今天我休息,花花洗漱完,我再去洗漱。

并行:在单CPU中多道程序设计系统中,进程被交替执行,表现出一种并发的外部特种;在多处理器系统中,进程不仅可以交替执行,而且可以重叠执行。在多核CPU上的程序才可实现并行处理。从而可知,并行是针对多处理器而言的。并行是同时发生的多个并发事件,具有并发的含义,但并发不一定并行,也亦是说并发事件之间不一定要同一时刻发生。举个例子,搬家了,厕所能同时容纳我和花花两个人了。

在Android包下android\app\ActivityThread.java类中,有这样一段代码

代码语言:javascript
复制
    // If the app is Honeycomb MR1 or earlier, switch its AsyncTask
    // implementation to use the pool executor.  Normally, we use the
    // serialized executor as the default. This has to happen in the
    // main thread so the main looper is set right.
    if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
        AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

AsyncTask中hide函数

代码语言:javascript
复制
/**
 * @hide
 */
public static void setDefaultExecutor(Executor exec) {
    sDefaultExecutor = exec;
}

通过查询,得知在Android 3.1以及之前的版本使用的是THREAD_POOL_EXECUTOR,之后使用的是SERIAL_EXECUTOR

代码语言:javascript
复制
    /**
     * May 2011: Android 3.1.
     */
    public static final int HONEYCOMB_MR1 = 12;

THREAD_POOL_EXECUTOR是一个自定义的线程池。多核时代的线程池意味着并行和异步,(其实这里说异步,并不确切,因为异步强调是多个工作线程完成同一个任务,侧重专业性和目的性)是一种高效的任务执行模式。

这个SERIAL_EXECUTOR同样也是以EXECUTOR结尾的,是不是另一种线程池呢?

代码语言:javascript
复制
/**
 * An {@link Executor} that executes tasks one at a time in serial
 * order.  This serialization is global to a particular process.
 */
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static class SerialExecutor implements Executor {
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    Runnable mActive;
    public synchronized void execute(final Runnable r) {
        mTasks.offer(new Runnable() {
            public void run() {
                try {
                    r.run();
                } finally {
                    scheduleNext();
                }
            }
        });
        if (mActive == null) {
            scheduleNext();
        }
    }
    protected synchronized void scheduleNext() {
        if ((mActive = mTasks.poll()) != null) {
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

Executor 接口如下:

代码语言:javascript
复制
public interface Executor {

/**
 * Executes the given command at some time in the future.  The command
 * may execute in a new thread, in a pooled thread, or in the calling
 * thread, at the discretion of the {@code Executor} implementation.
 *
 * @param command the runnable task
 * @throws RejectedExecutionException if this task cannot be
 * accepted for execution
 * @throws NullPointerException if command is null
 */
void execute(Runnable command);
}

看完这段代码,就恍然大悟,差一点就被AT的命名给坑了,原来SERIAL_EXECUTOR只是一个实现了Executor接口的内部静态类,内部真正执行任务的依然是THREAD_POOL_EXECUTOR线程池,它存在的作用就是,把任务队列化,前一个任务执行完毕后,后一个任务才会被提交到线程池中,那么线程池中始终是只有一个工作线程在执行任务,也只有一个任务,这样的AT就变成了串行工作模式。虽然效率降低了,但是提高了稳定性,避免了因任务过多,导致线程池缓冲队列膨胀带来的FC隐患。

总结:AT中doInBackgroundonPostExecute等方法,只是一些回调接口,真正实现异步访问的是FutureTask,包括AT的取消,也是通过中断FutureTask中的任务。FutureTask任务的执行又需要线程池来做支撑,所以AT又在外面包了一层线程池的实现,只不过这个线程池比较奇葩,通过一个串行工作模式,逐一将任务丢进池内。

说了这么多,为了提高执行效率,我们得发挥起来才能对的起各大厂商的真八核。接下来为大家介绍一个高效的并行模式,Master-Worker。

Master-Worker,的核心思想就是又两类进程协调工作:Master线程和Worker线程。Master线程负责接收和分配任务,Worker线程负责处理子任务。当各个Worker进行将子任务处理完成后,将处理结果返回给Master线程,由Master进程做归纳和汇总,从而得到系统的最终结果。

Master-Worker工作示意图

Master-Worker模式好处就是,它能够将一个大任务,并行执行,从而提高系统的执行效率。Client作为请求者,提交任务,Master线程会分配任务并立即返回,并不会等待全部子任务执行完毕后再返回。根据上面对异步的解释,Master-Worker模式的目的性很强,Master和Worker线程是协调完成的,因此Master-Worker模式是典型的利用多线程处理数据的异步工作模式。

我的舍友花花,最近在温习基础知识,刚刚看到九九乘法表,瞥了一眼,发现他的笔记上还再用双层for循环嵌套的方式进行计算,这种方法只适合打印出美观的阶梯式乘法表,但是如果放到项目中,这种算法太慢,效率太低。如果涉及平方和相加就更慢了,更甭提立方和了。

于是,我通过Master-Worker模式,写了一个demo,供大家参考。

依然提前写完了,再次附上链接。

Master-Worker框架实现

至此,我所认识的ExecutorService介绍完毕,可能有些遗忘的地方,有些地方的讲解可能不到位或者有错误,希望朋友们多提意见,本人会持续更新博客。

片尾Tip:3月15日,ios 8.3Beta。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015.03.15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档