标签:android开发
尊重原创:http://blog.csdn.net/yuanzeyao/article/details/42583215
在Android中,和异步执行相关的两个类就是Handler和AsyncTask,所以Android开发人员对于这两个类是再熟悉不过了,所以这里我不是讲解AsyncTask怎么使用,而是想分析一下AsyncTask中线程池的调度过程,然后简单的介绍一下AsyncTask的源码以及Android3.0前后,AsyncTask中线程池的区别。
在正式学习AsyncTask中的线程池之前,我们首先回忆一下java中的线程池的内容。就从Executor开始吧,Executor就是一个接口,代码如下:
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the <tt>Executor</tt> implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution.
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}我们来分析一下execute这个方法的方法签名,可以发现有一个Runnable类型参数和会抛出两个异常:
Runnable:这里我们就把他当作一个线程吧。
RejectedExecutionException:通过execute方法无法将该任务加入任务队列就会有该异常。
NullPointerException:就是加入的任务时空的。
通过jdk1.6官方文档,可以知道,有一个接口继承了Executor,这个接口就是ExecutorService
public interface ExecutorService extends Executor {
/**
不再接纳新的任务,但是之前的任务会继续执行
*/
void shutdown();
/**
不再接纳新的任务,并且之前的任务也会终止(但是不一定终止成功)
返回还没有开始的任务列表
*/
List<Runnable> shutdownNow();
/**
向任务队列添加一个任务,并且返回一个Future对象
Future对象通过get方法可以拿到返回结果,注意这里可是Callable对象
*/
<T> Future<T> submit(Callable<T> task);
/**
这个方法也是添加一个任务,不过这里传入的是Callable对象,并多了一个返回值类型参数
*/
<T> Future<T> submit(Runnable task, T result);
/**
添加一个任务
*/
Future<?> submit(Runnable task);
}这个接口比Executor对了几个方法,其中几个比较重要的方法我也已经贴出并给出了解释,这里出现了几个新的类型,Callable,Future。首先来分析一下Callable
/**
* A task that returns a result and may throw an exception.
* Implementors define a single method with no arguments called
* <tt>call</tt>.
*
* <p>The <tt>Callable</tt> interface is similar to {@link
* java.lang.Runnable}, in that both are designed for classes whose
* instances are potentially executed by another thread. A
* <tt>Runnable</tt>, however, does not return a result and cannot
* throw a checked exception.
*
* <p> The {@link Executors} class contains utility methods to
* convert from other common forms to <tt>Callable</tt> classes.
*
* @see Executor
* @since 1.5
* @author Doug Lea
* @param <V> the result type of method <tt>call</tt>
*/
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}1、Runnable是run方法,而Callable是call方法
2、Runnable中的run方法没有返回值,而call方法时有返回值的
3、Runnable中run方法不会抛异常,而call方法会抛异常
所以如果我们遇到了Callable方法就暂且将它和Runnable同等对待吧。
下面再来看看Future这个类
public interface Future<V> {
/**
* Attempts to cancel execution of this task. This attempt will
* fail if the task has already completed, has already been cancelled,
* or could not be cancelled for some other reason. If successful,
* and this task has not started when <tt>cancel</tt> is called,
* this task should never run. If the task has already started,
* then the <tt>mayInterruptIfRunning</tt> parameter determines
* whether the thread executing this task should be interrupted in
* an attempt to stop the task.
*
* <p>After this method returns, subsequent calls to {@link #isDone} will
* always return <tt>true</tt>. Subsequent calls to {@link #isCancelled}
* will always return <tt>true</tt> if this method returned <tt>true</tt>.
*
* @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
* task should be interrupted; otherwise, in-progress tasks are allowed
* to complete
* @return <tt>false</tt> if the task could not be cancelled,
* typically because it has already completed normally;
* <tt>true</tt> otherwise
*/
boolean cancel(boolean mayInterruptIfRunning);
/**
* Returns <tt>true</tt> if this task was cancelled before it completed
* normally.
*
* @return <tt>true</tt> if this task was cancelled before it completed
*/
boolean isCancelled();
/**
* Returns <tt>true</tt> if this task completed.
*
* Completion may be due to normal termination, an exception, or
* cancellation -- in all of these cases, this method will return
* <tt>true</tt>.
*
* @return <tt>true</tt> if this task completed
*/
boolean isDone();
/**
* Waits if necessary for the computation to complete, and then
* retrieves its result.
*
* @return the computed result
* @throws CancellationException if the computation was cancelled
* @throws ExecutionException if the computation threw an
* exception
* @throws InterruptedException if the current thread was interrupted
* while waiting
*/
V get() throws InterruptedException, ExecutionException;
/**
* Waits if necessary for at most the given time for the computation
* to complete, and then retrieves its result, if available.
*
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return the computed result
* @throws CancellationException if the computation was cancelled
* @throws ExecutionException if the computation threw an
* exception
* @throws InterruptedException if the current thread was interrupted
* while waiting
* @throws TimeoutException if the wait timed out
*/
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}Future其实也是一个泛型接口,其中每个方法都比较重要我们一一来看:cancel:取消一个任务,不过当一个任务已经完成时,取消就会失败,这个方法有一个参数mayInterruptIfRunning,如果传入的是true,那么即使你的任务已经开始,那么也会试图中断任务所在线程
isDone:如果一个任务执行完毕,那么这里返回true
get:该方法有两个重载方法,首先看没有参数的,这个方法时一个同步方法,只到任务成功执行完毕才返回,如果任务取消或者中断,都会抛出异常,有参数的get方法就是限定了等待时间,如果在指定时间内没有返回,那么就不再等待。
由于AsyncTask中涉及到了一个FutureTask这个类,并且这个类和Future有关,所以在这里一起也看看FutureTask的内容。由于FutureTask的代码比较多,这里我先贴出它的签名
public class FutureTask<V> implements RunnableFuture<V>
这个类有一个done方法由于在AsyncTask中会使用到,所以在这里说一下
/**
* Protected method invoked when this task transitions to state
* <tt>isDone</tt> (whether normally or via cancellation). The
* default implementation does nothing. Subclasses may override
* this method to invoke completion callbacks or perform
* bookkeeping. Note that you can query status inside the
* implementation of this method to determine whether this task
* has been cancelled.
*/
protected void done() { }/**
* Creates a <tt>FutureTask</tt> that will upon running, execute the
* given <tt>Callable</tt>.
*
* @param callable the callable task
* @throws NullPointerException if callable is null
*/
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
sync = new Sync(callable);
}
/**
* Creates a <tt>FutureTask</tt> that will upon running, execute the
* given <tt>Runnable</tt>, and arrange that <tt>get</tt> will return the
* given result on successful completion.
*
* @param runnable the runnable task
* @param result the result to return on successful completion. If
* you don‘t need a particular result, consider using
* constructions of the form:
* <tt>Future<?> f = new FutureTask<Object>(runnable, null)</tt>
* @throws NullPointerException if runnable is null
*/
public FutureTask(Runnable runnable, V result) {
sync = new Sync(Executors.callable(runnable, result));
}
下面继承看RunnableFuture这个接口
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}上面是jdk中和线程池关系比较紧密的几个接口和类,下面我就来看看jdk中的一个具体的线程池类ThreadPoolExecuter,这个类实现了ExecuteService接口,并且在Android3.0系统之前实用的的就是这个线程池
先看看ThreadPoolExecuter的构造函数的签名:(还有其他的构造函数,这里我那最简单的构造函数说明)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
corePoolSize:池中所保存的线程数,包括空闲线程
maximumPoolSize:池中允许的最大线程数
keepAliveTime:当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间
unit:keepAliveTime 参数的时间单位
workQueue:执行前用于保持任务的队列
这里我们要重点理解corePoolSize,maximumPoolSize,workQueue这三个参数的意义。
当我们向线程池中添加一个任务时
1、如果线程数<corePoolSize,那么创建一个线程,不管此时是否有线程空闲
2、如果线程数=corePoolSize,如果有空闲线程,那么空闲线程处理加入的任务,如果没有空闲线程,那么加入workQueue中。只到workQueue线程已经满了,才会创建新的线程来处理新加入的任务,如果此时创建的线程数超过了maximumPoolSize,
那么就会抛RejectedExecutionException异常。
3、如果线程数>corePoolSize时,那么说明workQueue已经满了。
通过以上的描述,说明如果workQueue是一个无界队列,那么maximumPoolSize就没有意义了。
好了,关于线程池的分析就到这里,我们开始看看AsyncTask的源码吧。
先看看它的一些比较重要的属性吧
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 10;
private static final BlockingQueue<Runnable> sWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
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 ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);1、AsyncTask中的线程池,保存的线程数量是5个,数量大于5个的线程如果空闲10s中就会销毁掉。
2、最大的线程数是128个,任务队列的容量是10,按照前面的分析,最多可以添加128+10个任务,加入139个任务时,程序就会崩溃
3、线程池是 static的,也就是说所有的AsyncTask公用一个线程池(一个应用之类的AsyncTask)。
下面看看AsyncTask的构造方法
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return doInBackground(mParams);
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
Message message;
Result result = null;
try {
result = get();
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));
message.sendToTarget();
return;
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(AsyncTask.this, result));
message.sendToTarget();
}
};
} private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}接下来使用mWorker为参数创建了一个FutureTask对象,同样改写了done方法,前面我们已经介绍了done方法是在任务状态变为isdone时调用的,在done方法里面,我们会通过Future的get方法拿到结果。然后通过Handler将结果发送到UI线程处理,这里Handler处理的消息可能是MESSAGE_POST_CANCEL(取消),也可能是MESSAGE_POST_RESULT(正常完毕)。其中Message的obj是一个AsyncTaskResult类型,这个类型就是包装了当前AsyncTask和返回结果的。
我们启动一个AsyncTask就是调用execute方法,那么我们看看execute方法做了什么吧
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
sExecutor.execute(mFuture);
return this;
}加入线程池,那么其实调用的就是mWorker中的call方法,其实调用的就是doInBackground方法,当任务状态变为isdone时,就会向Handler发送消息,这个Handler是InternalHandler类型
private static class InternalHandler extends Handler {
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult result = (AsyncTaskResult) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
case MESSAGE_POST_CANCEL:
result.mTask.onCancelled();
break;
}
}
} private void finish(Result result) {
if (isCancelled()) result = null;
onPostExecute(result);
mStatus = Status.FINISHED;
}在finish中如果AsycnTask已经取消了,那么将结果设置为null,否则调用onPostExecute并将mStatus设置为FINISH。所以一个AsyncTask只能被执行一次,相同的任务需要多执行多次时,只能创建多次AsyncTask。当消息是MESSAGE_POST_CANCEL时,就是调用了AsyncTask的cancel方法时,会出现的情况。MESSAGE_POST_PROGRESS消息大家可以自己分析。
到这里2.2中AsyncTask的调度过程也算是分析完了,下面分析4.1中AsyncTask的不同点,其中最大的不同点就是线程池的不一样
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
/**
* 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();我们看看execute方法到底用的是哪个线程池
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}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);
}
}
}所以最大的改变也很容易看出来就是限制了向线程池THREAD_POOL_EXECUTOR中加入任务的速度,只能上个任务执行完毕后才能加入下一个任务。所以相当于是一个线程在工作
所以在3.0后的版本中,我们通常不调用execute方法,而是调用executeonExecutor方法,自己定义自己的线程池,然后传递进入。
标签:android开发
原文地址:http://blog.csdn.net/yuanzeyao/article/details/42583215