asynctask的并行与串行

本文深入探讨了Android中AsyncTask的工作原理,重点讲解了其串行与并行执行模式的区别,并通过实例演示了不同执行模式下任务调度的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考:Android源码分析—带你认识不一样的AsyncTask(串并行)

查看asynctask源码:

    /**
     * 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 volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

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

由于 SERIAL_EXECUTOR 被声明为static,
所以,同一个进程里的AsyncTask都会共享这个线程池,这就意味着,在同一个进程里,前面的线程不结束,后面的线程就会被挂起


    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // We want at least 2 threads and at most 4 threads in the core pool,
    // preferring to have 1 less than the CPU count to avoid saturating
    // the CPU with background work
    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;

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

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

	/**
     * An {@link Executor} that can be used to execute tasks in parallel.//平行、并列
     */
    public static final Executor THREAD_POOL_EXECUTOR;	//支持2到4个线程并行的线程池:

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

使用AsyncTask执行任务的时候,可使用AsyncTask.executeOnExecutor(THREAD_POOL_EXECUTOR)来让你的任务跑在并行的线程池上,
避免出现并前面线程阻塞的情况。

当然,如果你的CPU核心数够多,2到4个线程的并行度不满足的话,也可以自定义一个线程池来执行AsyncTask,
不过这样的话,要注意自己维护这个线程池的初始化,释放等等操作了。

使用AsyncTask的规则

AsyncTask的类必须在UI线程加载(从4.1开始系统会帮我们自动完成)
AsyncTask对象必须在UI线程创建
execute方法必须在UI线程调用
不要在你的程序中去直接调用onPreExecute(),onPostExecute, doInBackground, onProgressUpdate方法
一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常
AsyncTask不是被设计为处理耗时操作的,耗时上限为几秒钟,如果要做长耗时操作,强烈建议你使用Executor,ThreadPoolExecutor以及FutureTask
在1.6之前,AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务

测试串行与并行

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn1"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:onClick="onClick"
        android:text="串行"
        android:textColor="#ff0000"
        android:textSize="16sp" />

    <Button
        android:id="@+id/btn2"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:onClick="onClick"
        android:text="并行"
        android:textColor="#ff0000"
        android:textSize="16sp" />

</LinearLayout>

代码:

public class TestActivity extends AppCompatActivity {

    private static final String TAG = "TestActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
    }

    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn1:
                new MyAsyncTask("AsyncTask#1").execute("");
                new MyAsyncTask("AsyncTask#2").execute("");
                new MyAsyncTask("AsyncTask#3").execute("");
                new MyAsyncTask("AsyncTask#4").execute("");
                new MyAsyncTask("AsyncTask#5").execute("");
                break;

            case R.id.btn2:
                new MyAsyncTask("AsyncTask#1").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
                new MyAsyncTask("AsyncTask#2").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
                new MyAsyncTask("AsyncTask#3").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
                new MyAsyncTask("AsyncTask#4").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
                new MyAsyncTask("AsyncTask#5").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
                break;

        }
    }

    private static class MyAsyncTask extends AsyncTask<String, Integer, String> {

        private String mName = "AsyncTask";

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

        @Override
        protected String doInBackground(String... params) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return mName;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Log.e(TAG, result + "execute finish at " + df.format(new Date()));
        }
    }

}

android8.0上测试结果:

点击按钮1:开始到结束15秒,顺序执行而且每次间隔3秒,很明显串行

TestActivity: AsyncTask#1execute finish at 2018-08-01 20:36:17
TestActivity: AsyncTask#2execute finish at 2018-08-01 20:36:20
TestActivity: AsyncTask#3execute finish at 2018-08-01 20:36:23
TestActivity: AsyncTask#4execute finish at 2018-08-01 20:36:26
TestActivity: AsyncTask#5execute finish at 2018-08-01 20:36:29

点击按钮2:线程1234一起执行(验证了最多四个线程同时执行),然后执行线程5间隔三秒,很明显并行

TestActivity: AsyncTask#2execute finish at 2018-08-01 20:41:15
TestActivity: AsyncTask#3execute finish at 2018-08-01 20:41:15
TestActivity: AsyncTask#4execute finish at 2018-08-01 20:41:15
TestActivity: AsyncTask#1execute finish at 2018-08-01 20:41:15
TestActivity: AsyncTask#5execute finish at 2018-08-01 20:41:18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值