• 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,当源码触发了系统限制或错误时,此时我们要反思可能不是系统的问题,而是我们的代码或实现机制问题。如何解决需谨慎思考,不可盲从高手的解决办法,不是每个都能控制住这种源码级修改的引发的其它问题。

  • 相关阅读:
    兼容ie6的mvvm框架--san
    Parsing error: The keyword 'export' is reserved && error Parsing error: Unexpected token <
    Call to undefined function openssl_decrypt()
    css 陌生属性
    获取url
    relative 和 absolute
    SSL certificate problem: unable to get local issuer certificate 的解决方法
    使用wamp扩展php时出现服务未启动的解决方法
    php判断是不是移动设备
    js:不是空字符串的空字符串引起的bug
  • 原文地址:https://www.cnblogs.com/weiwelcome0/p/4183938.html
Copyright © 2020-2023  润新知