在操作系统中,线程是操作系统调度的最小单元,同时线程又是一种受限的系统资源,即线程不肯能无限制地产生,并且线程的创建和销毁都会有相应的开销。

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 tocreate 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()


那有没有更简单的方法呢,那就用到 HandlerThread .
HandlerThread 继承 Thread , 可以看它的 run 方法。
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, 并开始消息队列。
由于 HandlerThread 的 run 方法是一个无限循环,当不需要再使用 HandlerThread 时,可以通过使用它的 quit 或者 quitSafely 方法终止线程的执行。
使用例子

        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

核心线程固定,非核心线程数没有限制,当非核心线程闲置时会立即被回收。

适用于执行定时任务和具有固定周期的重复任务。








更多相关文章

  1. 〖Android〗简单隐藏Android虚拟键盘的方法
  2. Java Android 线程池
  3. android 引入jni 的so库的方法
  4. Android屏幕保持常亮的三种方法
  5. Android 关闭/打开多点触控 (Android中设置不能同时点击2个view的

随机推荐

  1. Android: change app names
  2. Android监听屏幕锁屏
  3. Android在内存中读取数据
  4. android WebView解析
  5. Android(安卓)拖拽效果实现代码分享 - OR
  6. Android(安卓)IPC 机制【1】--简介
  7. android 修改主题背景色
  8. sqlite android
  9. 【自定义控件】 ------- GridView
  10. android wiki