AsyncTask線程池異常RejectedExecutionException的解決


1,問題描述:

    開發的一項地圖應用中,要加載很多層的數據並展示出來,一般地圖都是瓦片的,那么不斷的滑動,隨着地圖的可見瓦片不同,需要將這些層的數據不斷的加載並顯示出來。此時我們使用了異步加載AsyncTask,但滑動了幾次或十幾次時,會出現“程序異常終止”,此時觀察后台日志,則報RejectedExecutionException。

    我們使用兩層異步任務來實現的,核心的代碼如下:

  private void loadLayers() {

      new LoadLayerAsyncTask(curShowLayers).execute(partExtentMinX, partExtentMinY, partExtentMaxX, partExtentMaxY);

  }

  //LoadLayerAsyncTask類的核心代碼如下:

public class LoadLayerAsyncTask extends AsyncTask<Double, Integer, ArrayList<SubjectOverlay>> {
@Override

	protected ArrayList<SubjectOverlay> doInBackground(Double... params) {
		ArrayList<SubjectOverlay> layerList= new ArrayList<SubjectOverlay>(); 
		
		if(showLayers!=null&&showLayers.size()>0){
			// 讀取部件數據文件
			for (LayerInfoBO layerInfo : showLayers) {
				LoadLayerInfoAsyncTask tempTask = new LoadLayerInfoAsyncTask(layerInfo);			
				tempTask.execute(params[0], params[1], params[2], params[3]);					
				
			}
    	    }
		return layerList; 
	}
}

  

2,問題分析:

    通過對這個異常搜索分析可知,是由於aysncTask線程池的數量限制為128個,當啟動的asynctask的個數超過這個時,則會引發線程池的rejectException.網絡上有很多牛人,采用了修改android源碼,修改限制數量或者調整線程池拒絕策略,來達到修復這個問題。我沒有讀過android源碼,但這個問題真的一定要修改android源碼嗎?

    android設備一般不會超過4個核心,128個線程數量相對較充裕,系統這么限制也較合理,那么一定是我們敲代碼的姿勢不對了。是的,你仔細看看上面的代碼,確實屬於姿勢不對了。

3,問題原因:

    想象我們的操作場景:手指滑動地圖,那么應當觸發上面個的loadLayers() 方法,這個方法會啟動一個一級后台線程LoadLayerAsyncTask。在這個線程的doInBackground方法中,我們可以看到它實際是啟用了n個二級線程LoadLayerInfoAsyncTask。也就是說我們滑動一次會啟動n個線程,滑動10次會啟動10*n個線程,當后台線程池中未執行完的線程數大於128,觸發系統限制是必然的了。

4,問題解決:

   解決這個問題的思路,有多種方法。此處列出2種,這兩種方法均隱含要求每次啟動的二級線程數<128:

   a, 在一級線程啟動二級線程前,我們先取消之前未執行完的二級線程,再啟動二級線程。

   b, 在啟動一級線程時,我們采用提示框機制,二級線程未執行完,則提示框不消失從而禁止用戶繼續滑動操作觸發啟動新的一級線程。

5,問題總結:

   1,初級的android開發者需謹慎使用這種二級線程機制。一級asynctask一般有提示框機制阻止用戶連續操作,隱性使線程數不會達到128個,故使用一級asynctask是較安全的。

   2,當源碼觸發了系統限制或錯誤時,此時我們要反思可能不是系統的問題,而是我們的代碼或實現機制問題。如何解決需謹慎思考,不可盲從高手的解決辦法,不是每個都能控制住這種源碼級修改的引發的其它問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM