AsyncTask 使用

本文深入探讨如何使用自定义Executor替代AsyncTask的SerialExecutor,详细解释ThreadPoolExecutor参数设置及其与系统负载的关系,帮助读者理解线程池的工作原理及合理配置。
摘要由CSDN通过智能技术生成
Executor exec = new ThreadPoolExecutor(15, 200, 10,  TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());  

               new DownloadTask().executeOnExecutor(exec);  


这样就可以使用我们自定义的一个Executor来执行任务,而不是使用SerialExecutor。

上述代码的效果允许在同一时刻有15个任务正在执行,并且最多能够存储200个任务。

 这个可以解决AsyncTask 的并发现象:

AsyncTask 错误java.lang.IllegalStateException: Cannot execute task: the task has already been executed

意思就是 一个对象只能调用一次;

 

ThreadPoolExecutor 参数:

 

JDK1.5中引入了强大的concurrent包,其中最常用的莫过了线程池的实现ThreadPoolExecutor,它给我们带来了极大的方便,但同时,对于该线程池不恰当的设置也可能使其效率并不能达到预期的效果,甚至仅相当于或低于单线程的效率。

ThreadPoolExecutor类可设置的参数主要有:

  • corePoolSize

核心线程数,核心线程会一直存活,即使没有任务需要处理。当线程数小于核心线程数时,即使现有的线程空闲,线程池也会优先创建新线程来处理任务,而不是直接交给现有的线程处理。

核心线程在allowCoreThreadTimeout被设置为true时会超时退出,默认情况下不会退出。

  • maxPoolSize
当线程数大于或等于核心线程,且任务队列已满时,线程池会创建新的线程,直到线程数量达到maxPoolSize。如果线程数已等于maxPoolSize,且任务队列已满,则已超出线程池的处理能力,线程池会拒绝处理任务而抛出异常。

  • keepAliveTime

当线程空闲时间达到keepAliveTime,该线程会退出,直到线程数量等于corePoolSize。如果allowCoreThreadTimeout设置为true,则所有线程均会退出直到线程数量为0。

  • allowCoreThreadTimeout

是否允许核心线程空闲退出,默认值为false。

  • queueCapacity

任务队列容量。从maxPoolSize的描述上可以看出,任务队列的容量会影响到线程的变化,因此任务队列的长度也需要恰当的设置。


线程池按以下行为执行任务

  1. 当线程数小于核心线程数时,创建线程。
  2. 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
  3. 当线程数大于等于核心线程数,且任务队列已满
    1. 若线程数小于最大线程数,创建线程
    2. 若线程数等于最大线程数,抛出异常,拒绝任务


系统负载

参数的设置跟系统的负载有直接的关系,下面为系统负载的相关参数:

  • tasks,每秒需要处理的最大任务数量
  • tasktime,处理第个任务所需要的时间
  • responsetime,系统允许任务最大的响应时间,比如每个任务的响应时间不得超过2秒。


参数设置


corePoolSize:

每个任务需要tasktime秒处理,则每个线程每钞可处理1/tasktime个任务。系统每秒有tasks个任务需要处理,则需要的线程数为:tasks/(1/tasktime),即tasks*tasktime个线程数。假设系统每秒任务数为100~1000,每个任务耗时0.1秒,则需要100*0.1至1000*0.1,即10~100个线程。那么corePoolSize应该设置为大于10,具体数字最好根据8020原则,即80%情况下系统每秒任务数,若系统80%的情况下第秒任务数小于200,最多时为1000,则corePoolSize可设置为20。


queueCapacity:

任务队列的长度要根据核心线程数,以及系统对任务响应时间的要求有关。队列长度可以设置为(corePoolSize/tasktime)*responsetime: (20/0.1)*2=400,即队列长度可设置为400。

队列长度设置过大,会导致任务响应时间过长,切忌以下写法:

LinkedBlockingQueue queue = new LinkedBlockingQueue();

这实际上是将队列长度设置为Integer.MAX_VALUE,将会导致线程数量永远为corePoolSize,再也不会增加,当任务数量陡增时,任务响应时间也将随之陡增。


maxPoolSize:

当系统负载达到最大值时,核心线程数已无法按时处理完所有任务,这时就需要增加线程。每秒200个任务需要20个线程,那么当每秒达到1000个任务时,则需要(1000-queueCapacity)*(20/200),即60个线程,可将maxPoolSize设置为60。


keepAliveTime:

线程数量只增加不减少也不行。当负载降低时,可减少线程数量,如果一个线程空闲时间达到keepAliveTiime,该线程就退出。默认情况下线程池最少会保持corePoolSize个线程。


allowCoreThreadTimeout:

默认情况下核心线程不会退出,可通过将该参数设置为true,让核心线程也退出。


以上关于线程数量的计算并没有考虑CPU的情况。若结合CPU的情况,比如,当线程数量达到50时,CPU达到100%,则将maxPoolSize设置为60也不合适,此时若系统负载长时间维持在每秒1000个任务,则超出线程池处理能力,应设法降低每个任务的处理时间(tasktime)。

===============================================================================

package com.redoor.rcs.async;

import java.util.List;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;

import com.redoor.rcs.common.AppContext;
import com.redoor.rcs.constants.ComConstants;
import com.redoor.rcs.db.SQLiteManage;
import com.redoor.rcs.info.MessageDTO;
import com.redoor.rcs.utils.MyLog;

/**
 * @version 1.0
 *
 * @author DongXiang
 * 
 * @action 加载单聊消息列表,每次都逐增SQLiteManage.LOAD_MSG_PER_COUNT=0x14条加载数据。
 * 
 * @time 2017年4月8日上午10:55:33
 * 
 */
public class ReqLocalMessageDTOData_PerLoadCount  extends AsyncTask<String,Integer, List<MessageDTO>>{
	
	private List<MessageDTO> msgDTOListPoint=null;
	private String peercountId="";
	private Context asContext=null;
	private Handler asHandler=null;
	private boolean isShowLoading;
	
	private volatile boolean stopFlag=true;

	public ReqLocalMessageDTOData_PerLoadCount(List<MessageDTO> nowMsgDTOListPoint,String peeraccountid,
			Handler asHandler,boolean isShowLoading) {
		super();
		this.msgDTOListPoint = nowMsgDTOListPoint;
		this.peercountId=peeraccountid;
		this.asHandler = asHandler;
		this.isShowLoading=isShowLoading;
		asContext=AppContext.getContext();
	}

	@Override
	protected void onPreExecute() {
		super.onPreExecute();
		
		if (isShowLoading) {
			
			
			new Thread(new Runnable() {
				int currentSize=msgDTOListPoint.size();
//				int perLoadcount=SQLiteManage.LOAD_MSG_PER_COUNT;//进度设置成 这个数字
				
				@Override
				public void run() {
					while (stopFlag) {
						try {
							publishProgress(msgDTOListPoint.size()-currentSize);
							Thread.sleep(200);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
			}).start();
		}
	}

	@Override
	protected List<MessageDTO> doInBackground(String... params) {
		SQLiteManage.getInstance().queryMessageDTOList_Per_LoadCount(msgDTOListPoint,peercountId);
		
		if (isShowLoading) {
			stopFlag=false;
			publishProgress(SQLiteManage.LOAD_MSG_PER_COUNT);
		}
		return null;
	}
	
	@Override
	protected void onProgressUpdate(Integer... values) {
		super.onProgressUpdate(values);
		MyLog.e("ReqLocalRoomListData_PerLoadCount", " onProgressUpdate values "+(values.length>0?values[0]:"没有进度"));
		if (isShowLoading) {
			if ((values.length>0)&&(values[0]>=SQLiteManage.LOAD_MSG_PER_COUNT)) {
				
				
			}
		}
	}

	@Override
	protected void onCancelled() {
		super.onCancelled();
		MyLog.e("ReqLocalRoomListData_PerLoadCount ", "onCancelled is actioning");
		sendHandlerMsg(ComConstants.HTTP_CANCLE);
		
	}

	@Override
	protected void onPostExecute(List<MessageDTO> result) {
		super.onPostExecute(result);
		MyLog.e("ReqLocalRoomListData_PerLoadCount ", "onPostExecute is actioning");

		sendHandlerMsg(ComConstants.HTTP_OK);
		
	}
	
	/**
	 * 
	 * @param reqResult 返回 响应值;
	 */
	private void sendHandlerMsg(int reqResult){
		if (isShowLoading) {
			
		}
		stopFlag=false;
		asHandler.sendMessage(asHandler.obtainMessage(reqResult, ComConstants.MESSAGE_DTO_LIST_VALUE, -1, msgDTOListPoint));
			
	}
	

}

================原版 ============

class DownloadTask extends AsyncTask<Void, Integer, Boolean> {

	@Override
	protected void onPreExecute() {
		progressDialog.show();
	}

	@Override
	protected Boolean doInBackground(Void... params) {
		try {
			while (true) {
				int downloadPercent = doDownload();
				publishProgress(downloadPercent);
				if (downloadPercent >= 100) {
					break;
				}
			}
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	@Override
	protected void onProgressUpdate(Integer... values) {
		progressDialog.setMessage("当前下载进度:" + values[0] + "%");
	}

	@Override
	protected void onPostExecute(Boolean result) {
		progressDialog.dismiss();
		if (result) {
			Toast.makeText(context, "下载成功", Toast.LENGTH_SHORT).show();
		} else {
			Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();
		}
	}
}

=================  拓展连接 ================

http://blog.csdn.net/guolin_blog/article/details/11711405#



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值