在操作系统中,线程是操作系统调度的最小单元,同时线程又是一种受限的系统资源,即线程不肯能无限制地产生,并且线程的创建和销毁都会有相应的开销。
Android 的线程分主线程和子线程。主线程主要处理和界面相关的工作,子线程,也被称为工作线程,执行耗时工作。
Android 中的线程形态除了 Thread 外,还包含 AsyncTask、Handler 以及 IntentService, 它们在底层实现也是线程。
一、AsyncTask
1、 AsyncTask 是轻量级的异步任务,是一个抽象的泛型类,内部使用封装了 Thread 和 Handler ,使用了线程池执行了后台任务,然后把执行的进度和最终的结果传递会主线程,在主线程中更新 UI.
AsyncTask 不适合进行特别耗时的后台任务,对于特别耗时的任务尽量使用线程池。
/** * AsyncTask 是一个泛型的抽象类 * @param <Params> 输入的参数类型 * @param <Progress> 后台任务的执行进度类型 * @param <Result> 后台任务的返回结果类型 */ public abstract class AsyncTask<Params, Progress, Result>
2、AsyncTask 的四个核心方法
/** * 在主线程中执行,在异步任务执行之前,此方法会被调用,用于做一些准备工作 */ @Override protected void onPreExecute() { super.onPreExecute(); } /** * 在线程池中执行,此方法用于执行异步任务,在此方法中通过 publishProgress 方法来更新任务的进度, * publishProgress 方法会调用 onProgressUpdate 方法。 * 同时此方法返回结算结果给 onPostExecute 方法 * @param params 表示输入的参数 * @return */ @Override protected Params doInBackground(Params... params) { } /** * 在主线程中执行,当后台任务的执行进度发生变化时,此方法会被调用 * @param values */ @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } /** * 在主线程中执行,在异步任务执行之后,此方法会执行。 * 如果 onCancelled() 方法调用之后,该方法则不会执行 * @param result 后台任务的返回值,即 doInBackground 的返回值。 */ @Override protected void onPostExecute(String result) { super.onPostExecute(result); }
3、AsyncTask 在具体使用中一些条件限制
(1) AsyncTask 的类必须在主线程中加载;
(2) AsyncTask 的对象必须在主线程中创建;
(3) execute 方法必须在 UI 线程调用;
(4) 不要在程序中直接调用 onPreExecute()、onPostExecute()、doInBackgroud 和 onProgressUpdate 方法;
(5) 一个 AsyncTask 对象只能执行一次,即只能调用一次 execute 方法,否则会报运行异常;
(6) 在 Android 1.6 之前,AsyncTask 是串行执行任务, Android 1.6 的时候 AsyncTask 采用线程池处理并行任务。在 Android 3.0 开发,AsyncTask 又采用了一个线程来串行执行任务。 如果现在 Android 3.0 以后并行执行任务,可通过 executeOnExecutor 方法来实现。
4、AsyncTask 的工作原理
以 AsyncTask.execute(...) 方法为入口分析,execute(...) 方法调用了executeOnExecutor(...) 方法
public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, 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; // 这里调用了 AsyncTask 的 onPreExecute 方法, onPreExecute 方法 是一个空方法,需要我们自己在 // 实现自己的 AsyncTask 中重写改方法,做一些准备工作 // 在主线程中执行 onPreExecute(); mWorker.mParams = params; // 把任务交给线程池 sDefaultExecutor 执行 // mFuture 是 FutureTask 对象,FutureTask 是一个并发类, 在这里充当 Runnable 作用 exec.execute(mFuture); return this; }
sDefaultExecutor 是一个串行的线程池,一个进程中所有的AsyncTask 全部在这个串行的线程池中排队执行。
AsyncTask 中有 SerialExecutor 和 THREAD_POOL_EXECUTOR 两个线程池,SerialExecutor 用于任务的排队,
THREAD_POOL_EXECUTOR 用于真正执行任务。
public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); 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) { // 将mFuture 即 r 插入到任务队列 mTasks 中 mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); // 如果没有没有正在活动的任务,则会执行下一个任务, 这样保证了所有的任务时一个一个执行 // 所以,在默认情况下,AsyncTask 是串行执行的 if (mActive == null) { scheduleNext(); } } // 从任务队列中取出一个任务,如果这个任务不为空,则交给线程池执行 protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { // 真正执行任务 THREAD_POOL_EXECUTOR.execute(mActive); } } }
THREAD_POOL_EXECUTOR 线程池执行的任务,是传进来的mFuture. mFuture 是 FutureTask 的一个对象,FutureTask 是一个并发类,在这里充当 Runnable 的作用。当 FutureTask 执行的时候会调用自身的 run() 方法,在run() 方法中调用了传进来的 Callable 对象的 call() 方法,即在这里的 mWoker.call() 方法
// mFuture 和 mWoker 是在 AsyncTask 创建时就已经创建了 mFuture = new FutureTask<Result>(mWorker); public void run() { ... try { Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { // 执行传进来的 Callable 对象的 call 方法 // 这里我们传进去的是 mWorker result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result); } ... } mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked // 这里执行 AsyncTask 的 doInBackground 方法, 返回执行的结果; // 这是一个空方法,需要我们在实现自己的 AsyncTask 对象时重新的; // 注意,因为我们把 mWoker 传进了 mFuture 中,而 mFuture 是在线程池中执行的,所以, // 这里是在线程中,而不是在主线程中。 Result result = doInBackground(mParams); Binder.flushPendingCommands(); // 把 doInBackground 执行后返回的结果,传进 postResult() 方法中 return postResult(result); } };在mWoker 的 call 方法中,将mTaskInvoked 设置为 true 表示当前任务已经被调用过,然后执行 AsyncTask 的 doInBackgroud 方法,接着将返回的值传递给 postResult(...) 方法
因为 postResult(...) 方法也是在线程池中执行的,所以,通过 Handler 发送消息
// postResult 方法通过 Handler 携带结果 result ,发送一个 MESSAG_POST_RESULT 消息 private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
在 InternalHandler 的 handleMessage(...) 方法中处理消息
// InternalHandler 是一个静态内部类 ,因为静态成员会在加载类的时候会进行初始化话, 为了能够将执行环 境切换到主线程中, // 这就要求AsyncTask 的对象必须在主线程中加载。 private static class InternalHandler extends Handler { 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: // 会调用 AsyncTask 的 onProgressUpdate(...) 方法,主线程中调用 result.mTask.onProgressUpdate(result.mData); break; } } }
// 如果任务已经被取消,则执行 onCancelled(result) 方法,这亦是一个空方法,需要自己重写实现 // 没有取消,则调用 onPostExecute(result) 方法, 整个过程结束。 private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { // 调用 AsyncTask 的 onPostExecute 方法,主线程中调用 onPostExecute(result); } mStatus = Status.FINISHED; }
到此,AsyncTask 整个运行结束。
5、AsyncTask 的使用例子
/** * 使用 AsyncTask 的一个例子,由于后台下载 * Created by Administrator on 2016/1/23. */ public class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { @Override protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize= 0; for (int i = 0; i < count; i++){ totalSize += Downloader.downloadFile(urls[i]); publishProgress((int)(i / (float)count) * 100); if (isCancelled()){ break; } } return null; } // 更新进程 @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } // 最后在主线程中执行 @Override protected void onPostExecute(Long aLong) { super.onPostExecute(aLong); } }
为了让 AsyncTask 在 Android3.0及版本以上并行,可以采用 AsyncTaskd 的 executeOnExecutor 方法
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){ new MyAsyncTask("AsyncTask#1").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ""); new MyAsyncTask("AsyncTask#2").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ""); new MyAsyncTask("AsyncTask#3").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ""); new MyAsyncTask("AsyncTask#4").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ""); }
二、HandlerThread
HandlerThread 的定义,Handy class for starting a new thread that has a looper. The looper can then used to create handler classes.
HandlerThread 本质上就是一个 Thread, 它继承 Thread.
我们可以在主线程中直接使用 Handler ,因为主线程中已经有了默认的 Looper, 但是如果我们在子线程中使用必须要创建一个 Looper, 还要通过 Looper.loop() 开启消息循环。
new Thread(new Runnable() { @Override public void run() { Log.i(TAG, "in startNewThread Thread id is " + Thread.currentThread().getId()); Looper.prepare(); Handler handler = new Handler(); Looper.loop(); } }).start();否则会抛出异常
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
public void run() { mTid = Process.myTid(); // 创建消息队列 Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); // 开启消息循环 Looper.loop(); mTid = -1; }HandlerThread 在run() 方法中已经为我们提供了 Looper, 并开始消息队列。
mHandlerThread = new HandlerThread("new handler"); mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()){ @Override public void handleMessage(Message msg) { Log.i(TAG, " handle massage msg " + msg.what + " in thread " + Thread.currentThread().getId() ); } }; } @Override protected void onDestroy() { super.onDestroy(); // 释放资源 mHandlerThread.quit(); }
三、IntentService
IntentService 是一种特殊的 Service , 它继承 Service 并且还是一个抽象类,必须创建它的子类才能使用IntentSercie.
IntentService 适用于非并发顺序处理后台任务,如果想要后台并发处理任务,还是得用 Service.
创建HandlerThread
<span style="font-size:18px;"> </span><span style="font-size:14px;">/** * 使用 HandlerThread */ public void onCreate() { // TODO: It would be nice to have an option to hold a partial wakelock // during processing, and to have a static startService(Context, Intent) // method that would launch the service & hand off a wakelock. super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); }</span>
发送消息
<span style="font-size:18px;"> </span><span style="font-size:14px;"> /** * 使用 mServiceHandler 发送消息,Handler 中 Looper 是顺序处理消息的。 * 这里显示了为什么 IntentService 会顺序执行后台任务 * @param intent 和 外界 startService(intent) 中的 intent 是完全一致的。 * @param startId */ public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); }</span>
处理消息
当 onHandleIntent(...) 方法执行后,使用 stopSelf(int startId) 方法来尝试停止服务,而不是stopSelf() 方法。是因为 stopSelf() 会立即停止服务,而如果这时候可能还有消息未处理,stopSelf(int startid) 则会等待所有的消息处理完毕后才终止服务
<span style="font-size:18px;"> </span><span style="font-size:14px;">/** * 处理发送过来的消息,然后停止 service * onHandleIntent 是个抽象方法,子类自己实现。 */ private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); } }</span>
四、 Android 中的线程池
使用线程池的优点
。重用线程池中的线程,避免因线程的创建和销毁所带来的性能开销;
。能有效控制线程池中的最大并发数,避免大量线程之间因互相抢占系统资源而导致最大阻塞现场。
Android 线程池来源于 Java 中的 Executor, Executor 只是接口,真正线程池的实现是 ThreadPoolExecutor
1、关于 ThreadPoolExecutor
<span style="font-size:18px;"> </span><span style="font-size:14px;"> /** * 线程池的真正实现 * @param corePoolSize 线程池的核心线程数 * 默认情况下,核心线程会在线程池中一直存活,即使它们处于闲置状态。如果将 ThreadPoolExecutor 的 allowCoreThreadTimeOut * 属性设置为 true, 那么闲置的核心线程在等待任务时会有超时策略,这个时间间隔由 keepAliveTime 所指定,等待时间超过 keepAliveTime * 所指定的时长后,核心线程就会被终止。 * @param maximumPoolSize 线程池所能容纳的最大线程数,当这个活动线程数达到这个数值后,后续的新任务将会被阻塞。 * @param keepAliveTime 非核心线程闲置时的超时时长,超过这个时长,费核心线程就会被回收。 * 当 ThreadPoolExecutor 的 allowCoreThreadTimeOut 属性设置为 true 时, keepAliveTime 同样会作用于核心线程。 * @param unit 指定 keepAliveTime 参数的时间单位 * 常用有 TimeUnit.MILLISECONDS , TimeUnit.SECONDS 以及 TimeUnit.MINUTES * @param workQueue 线程池中的任务队列,通过线程池的 execute 方法提交的 Runnable 对象会存储在这个参数中。 * @param threadFactory 线程工厂,为线程提供创建新线程的功能。 ThreadFactory 是一个接口,它只有一个方法 Thread newThread(Runnable r). */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) </span>
ThreadPoolExecutor 执行任务时的大致规则:
。1、如果线程池中的线程数量未达到核心线程的数量,会直接启动一个核心线程来执行任务;
。2、如果线程池中的线程数量已经达到或者超过核心线程的数量,那么任务会被插入到任务队列中排队等待执行;
。3、如果在 2 中因为任务队里已满,无法将任务插入到任务队列中,而此时如果线程数量未达到线程池规定的最大值,那么会立刻启动一个非核心线程执行任务;
。4、如果步骤 3 中线程数量已经达到线程池规定的最大值,那么就会拒绝执行此任务,ThreadPoolExecutor 会调用 RejectExecutionHandler 的 rejectedExecution 方法来通知调用者, 抛出 RejectedExecution.
2、线程池的分类
A. Executors.newFixedThreadPool
线程数量固定的线程池,当线程处于空闲状态时,它们并不会被回收,除非关闭线程池。如果提交的任务多于线程数,就把任务插入到任务队列中。
B. Executors.newSingleThreadExecutor
是一个退化了的大小为 1 的线程池。只有一个核心线程,它确保所有的任务都在同一线程中按顺序执行。
C. Executors.newCachedThreadPool
是一种线程数量不定的线程池,它只有非核心线程,最大线程数可以达到Integer.MAX_VALUE. 线程池中的空闲线程都有超时机制,时长为 60 秒,超过 60 秒闲置线程就会被回收。
适用于执行大量的耗时较少的任务。
D. Executors.newScheduledThreadPool
核心线程固定,非核心线程数没有限制,当非核心线程闲置时会立即被回收。
适用于执行定时任务和具有固定周期的重复任务。