参考: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