Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android編程入門 >> Android學習筆記:多個AsyncTask實例的並發問題

Android學習筆記:多個AsyncTask實例的並發問題

編輯:Android編程入門

AsyncTask是Android給開發者提供的一個簡單輕量級的多線程類,通過它我們可以很容易新建一個線程讓在後台做一些耗時的操作(如IO操作、網絡訪問等),並在這個過程中更新UI。之所以說它輕量級,是因為不需要直接使用Handler、Thread等知識,使用起來比較簡單,但也失去了一些靈活性,對於一些復雜的場景處理起來不方便。

如果一個APP進程中同時只創建和運行一個AsyncTask實例,則不會有任何問題。但如果在一個進程中如果有多個AsyncTask任務同時在執行,問題就比較復雜了。下面我們通過例子來看(我們例子是在Android 4中運行的)。

一、測試1(默認多個Task是串行執行的)

1、創建一個默認的app工程

2、創建一個類繼承AsyncTask,代碼如下

package com.example.asynctaskdemo;

import android.os.AsyncTask;

public class MyAsyncTask extends AsyncTask<String, Void, String>{
	
	private String name;
	
	public MyAsyncTask(String name){
		this.name = name;
	}

	@Override
	protected String doInBackground(String... params) {
		System.out.println(name+" is run "+System.currentTimeMillis()+" thread id "+Thread.currentThread().getId());
		try {
			Thread.sleep(1000*10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return null;
	}

}

3、在Activity的onCreate方法中使用該Task,代碼如下

@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		for(int i=1;i<5;i++){
			MyAsyncTask task = new MyAsyncTask("task"+i);
			task.execute(new String[0]);
		}
	}

  我們在調試窗口,觀察MyAsyncTask打印信息的間隔和順序。發現這創建的4個任務是串行執行的,並不是並發的。

研究了AsyncTask的實現細節,在創建一個AsyncTask並通過其execute方法啟動執行時,AsyncTask並不是創建一個獨立的線程去執行。AsyncTask是通過線程池來管理和調度進程中的所有Task的。

在 Android2.3以前的版本(SDK/API 大於等於10的版本)

多個AsyncTask任務是並發執行的,也就是說如果啟動多個task,則會並發執行。但並發執行的數量取決於AsyncTask內部的線程池限制數量。如果超過了這個限額,新的任務只能等待。

 在Android 3.0及以後版本(SDK/API 大於等於11的版本)

Google從Android 3.0開始對AsyncTask的調度執行做出了一些變化,對於execute提交的任務,按先後順序每次只運行一個。也就是說它是按提交的次序,每次只啟動一個線程執行一個任務,完成之後再執行第二個任務,也就是相當於只有一個後台線程在執行所提交的任務。上面的例子就驗證了這一點。

二、讓AsyncTask並發執行

因為默認情況下多個task是串行的,那怎麼樣讓並發執行呢?AsyncTask增加了一個新的接口executeOnExecutor,這個接口允許開發者提供自定義的線程池來運行和調度Thread。我們把上面代碼改下:

@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		for(int i=1;i<11;i++){
			MyAsyncTask task = new MyAsyncTask("task"+i);
			//task.execute(new String[0]);
			task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new String[0]);
		}
	}

  這裡我們使用了executeOnExecutor方法代替了execute方法。並且executeOnExecutor方法的第一個參數是一個預定義的線程池。這時這幾個task就可以並發執行了。這時我們觀察打印的結果,發現有5個任務並發執行,可以看出有5個不同的線程號,查看AsyncTask的源碼,發現並發線程數跟設備的cpu數量是有關的,因此不同的設備上可能看到的結果不完全一致,這點需要注意。只有前面的5個任務執行完後,才會執行後面的,並且通過打印的線程號可以看出,後面執行的任務是重用原來的線程,並沒有創建新的線程,這就是線程池的作用。

我們再來改下代碼,使用Android提供的另外一個預定義的線程池。代碼如下:

@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		for(int i=1;i<11;i++){
			MyAsyncTask task = new MyAsyncTask("task"+i);
			//task.execute(new String[0]);
			task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, new String[0]);
		}
	}

觀察打印信息我們可以發現,這和調用execute方法一樣,每個任務都是串行執行的。並且這個過程中最多創建了5個新的線程。

三、自定義線程池

我們可以利用java.util.concurrent.Executors中的各種靜態方法創建供AsyncTask執行的線程池 ,可以指定線程的數量和調度的方式。其方法很多,我們這裡介紹其中兩種較為常用的。

1、讓每個AsyncTask任務都單獨起一個線程執行,也就是說所有的都是並發的。代碼如:

@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
		for(int i=1;i<11;i++){
			MyAsyncTask task = new MyAsyncTask("task"+i);
			task.executeOnExecutor(newCachedThreadPool, new String[0]);
		}
	}

  通過觀察打印可以看出,這多個任務都是並發執行的。

2、創建指定線程數量的線程池,並發數上限就是指定的線程數。但新任務產生,沒有空閒的線程,就只能等待。代碼如:

@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3);
		for(int i=1;i<11;i++){
			MyAsyncTask task = new MyAsyncTask("task"+i);
			task.executeOnExecutor(newFixedThreadPool, new String[0]);
		}
	}

  通過觀察可以看出,有3個線程在並發執行。

總結下,從上面的例子中可以看出,如果一個進程中存在多個TASK需要並發執行的情況,那就需要用到AsyncTask一些更深的知識,需要考慮的問題更多。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved