AsyncTask 串行SERIAL_EXECUTOR,并行THREAD_POOL_EXECUTOR分析

AsyncTaks的内部实现机制相信已经很多人了解过了,但是多次调用excute()后,它是怎么执行的?带着这个疑问,来实践下看看

public class TestActivity extends AppCompatActivity {

    private static int ID = 0;
    private static final int TASK_COUNT = 20;
    private static ExecutorService SINGLE_TASK_EXECUTOR;
    private static ExecutorService FIXED_TASK_EXECUTOR;
    private static ExecutorService Cached_TASK_EXECUTOR;
	//自定义的3个线程池
    static {
        SINGLE_TASK_EXECUTOR = Executors.newSingleThreadExecutor();
        FIXED_TASK_EXECUTOR = Executors.newFixedThreadPool(7);
        Cached_TASK_EXECUTOR = Executors.newCachedThreadPool();
    }

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

        final ListView taskList = findViewById(R.id.task_list);
        taskList.setAdapter(new AsyncTaskAdapter(getApplication(), TASK_COUNT));
    }

	//List的适配器
    private class AsyncTaskAdapter extends BaseAdapter {
        private Context mContext;
        private LayoutInflater mFactory;
        private int mTaskCount;
        List<SimpleAsyncTask> mTaskList;

        public AsyncTaskAdapter(Context context, int taskCount) {
            mContext = context;
            mFactory = LayoutInflater.from(mContext);
            mTaskCount = taskCount;
            mTaskList = new ArrayList<>(taskCount);
        }

        @Override
        public int getCount() {
            return mTaskCount;
        }

        @Override
        public Object getItem(int position) {
            return mTaskList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = mFactory.inflate(R.layout.asynctask_demo_item, null);
                SimpleAsyncTask task = new SimpleAsyncTask(convertView);
                task.executeOnExecutor(SINGLE_TASK_EXECUTOR);

                mTaskList.add(task);
            }
            return convertView;
        }
    }

    private class SimpleAsyncTask extends AsyncTask<Void, Integer, Void> {
        private TaskItem mTaskItem;
        private String mName;

        public SimpleAsyncTask(View item) {
            mTaskItem = (TaskItem) item;
            mName = "Task #" + String.valueOf(++ID);
        }

        @Override
        protected void onPreExecute() {
            mTaskItem.setTitle(mName);
        }

        @Override
        protected Void doInBackground(Void... params) {
            int prog = 1;
            while (prog < 101) {
                SystemClock.sleep(50);
                publishProgress(prog);
                prog++;
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
        }

        
        @Override
        protected void onProgressUpdate(Integer... values) {
            mTaskItem.setProgress(values[0]);
        }

    }
}

class TaskItem extends LinearLayout {
    private TextView mTitle;
    private ProgressBar mProgress;

    public TaskItem(Context context) {
        super(context);
    }

    public TaskItem(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TaskItem(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    public void setTitle(String title) {
        if (mTitle == null) {
            mTitle = findViewById(R.id.task_name);
        }
        mTitle.setText(title);
    }

    public void setProgress(int prog) {
        if (mProgress == null) {
            mProgress = findViewById(R.id.task_progress);
        }
        mProgress.setProgress(prog);
    }
}

下面是xml代码:
activity_test:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.hao.Demo.TestActivity">

    <ListView
        android:id="@+id/task_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </ListView>
</LinearLayout>

asynatask_demo_item.xml

<com.hao.Demo.TaskItem xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">


    <TextView
        android:id="@+id/task_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Task #"/>

    <ProgressBar
        android:id="@+id/task_progress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="?android:attr/progressBarStyleHorizontal" />
    

</com.ryg.chapter_2.TaskItem>

当执行task.execute()也就是AsyncTask默认的执行方法时,可以看到只启动一个线程执行
在这里插入图片描述
下面接着调用

                task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);

然后会发现和上面的一样
那再换一个

                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

这个时候会发现同时启动了两个,说下线程池的CorePool为2个,具体CorePool是多少个在下面看源码才会知道
在这里插入图片描述
那下面切换到用自定义的线程池

	private static ExecutorService SINGLE_TASK_EXECUTOR;
    private static ExecutorService FIXED_TASK_EXECUTOR;
    private static ExecutorService Cached_TASK_EXECUTOR;

    static {
        SINGLE_TASK_EXECUTOR = Executors.newSingleThreadExecutor();
        FIXED_TASK_EXECUTOR = Executors.newFixedThreadPool(7);
        Cached_TASK_EXECUTOR = Executors.newCachedThreadPool();
    }
                task.executeOnExecutor(SINGLE_TASK_EXECUTOR);

发现是单线程执行;

                task.executeOnExecutor(FIXED_TASK_EXECUTOR);

这里按照定义的7个线程执行
在这里插入图片描述

                task.executeOnExecutor(Cached_TASK_EXECUTOR);

这个也是按照定义来执行。
下面来看源码里线程是怎么创建的,首先来看THREAD_POOL_EXECUTOR

	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;

可以看到Core_POOL_Size是根据CPU_COUNT的,也就是根据CPU核心数来计算,我的模拟器开的2核,所以是2个线程

//这个是THREAD_POOL_EXECUTOR要用的ThreadFactory,相当于计数的作用,使用了原子类
	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());
        }
    };
	
	/**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR;

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

注释写的很清楚,是并行执行task,本质上就是新建了个线程池


下面来看SERIAL_EXECUTOR,我把关键代码提取出来了
当直接调用execute()方法时,会执行sDefaultExecutor也就是串行线程池

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static class SerialExecutor implements Executor {
//		ArrayDuque双端队列存储Runnable
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;
//		新建Runnable调用传入的r的run并添加到mTasks队列中,调用scheduleNext()。
//		发现,,,这自己根本就没执行嘛,就是向多个要执行的任务放入队列中从而可以串行按序执行
        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }
//		可以看到使用了THREAD_POOL_EXECUTOR来执行
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

发现SerialExecutor 本质上是将多个要执行的任务进行串行处理,是线性调度的线程池,它本身并不执行任务,而是交给THREAD_POOL_EXECUTOR并行线程池去处理,执行完一个后再poll一个;
但是这样也有他的好处,保证了任务是有序完成的,如果直接并行并不能保证按序完成。

发布了38 篇原创文章 · 获赞 6 · 访问量 3409

猜你喜欢

转载自blog.csdn.net/qq_37704124/article/details/98522189
今日推荐