读书笔记(11) Android的线程和线程池

来源:互联网 发布:摇号机软件 编辑:程序博客网 时间:2024/06/05 17:31

这些读书笔记是根据《Android开发艺术探索》和《Android群英传》这两本书,然后将书上的一些知识点做一下记录。方便学习和理解,如果有存在侵犯版权的地方,还麻烦告知。个人强烈建议购买这两本书。真心不错。

本节是和《Android开发艺术探索》中的第11章 “Android的线程和线程池” 有关系,建议先买书查看这一章。

[]主线程和子线程

从用途上来说,线程分为主线程和子线程。

主线程是指进程拥有的线程,在java中默认的情况下一个进程只有一个线程,这个线程就是主线程。主线程也叫 UI 线程,主要的作用是运行四大组件以及处理它们和用户的交互。

子线程也叫工作线程,除了主线程以外的线程都是子线程。子线程主要处理执行耗时操作。

在Android中实现线程的方式除了Thread外,还有AsyncTask,IintentService,HandlerThread。

AsyncTask封装了线程池和Handler,主要是用于在子线程中更新UI。

IintentService是一个服务,在内部采用HandlerThread来执行任务。当任务执行完成后IintentService会自动退出。

HandlerThread是具有消息循环的线程,在内部可以使用Handler。

如果一个后台进程,这个进程中没有活动的四大组件。那么这个进程的优先级就会非常低,在内存不足时,很容易被系统杀死。这就是在广播中启动线程来执行耗时操作不安全的原因。

[]Android中的线程形态

{}AsyncTask

AsyncTask在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程并在主线程中更新UI。

AsyncTask经过几次修改,导致对于不同的API版本的AsyncTask具有不同的表现,尤其在多任务的并发执行上。

AsyncTask< Params, Progress, Result >是一个抽象的泛型类,提供了Params, Progress, Result 这三个泛型参数,如果 AsyncTask 不需要传递具体的参数,那么可以用Java.lang.Void代替。

Params:启动任务执行的输入参数的类型,比如请求的url。
Progress:后台任务的执行进度的类型。
Result :后台任务的返回结果的类型。

private  class **AsyncTask extends AsyncTask<String, Integer, String>{    /**     *     * @param params:String 对应AsyncTask中的第一个参数        * @return:String 对应AsyncTask的第三个参数     * 在线程池中执行,用于执行异步任务     * 通过调用 publishProgress()来调用onProgressUpdate()     * 返回值传递给onPostExecute()的参数     */    @Override    protected String doInBackground(String... params) {        return null;    }     /**     * 在主线程中执行,异步任务执行之前开始被调用,一般用于做一些准备工作     *      */    @Override    protected void onPreExecute() {        super.onPreExecute();    }     /**     *     * @param s:String 对应AsyncTask中的第三个参数     * 在主线程中执行,doInBackground()执行结束之后再运行,doInBackground()返回的值作为此方法的参数     *      */    @Override    protected void onPostExecute(String s) {        super.onPostExecute(s);    }     /**     *      * @param values:Integer 对应AsyncTask中的第二个参数     * 在主线程中执行,用于显示任务执行的进度     *      */    @Override    protected void onProgressUpdate(Integer... values) {        super.onProgressUpdate(values);    }    /**     *  在主线程中执行,异步任务取消时被调用     *      */    @Override    protected void onCancelled() {        super.onCancelled();    }}

执行AsyncTask

 new **AsyncTask().execute(Params... params);

onPreExecute()先执行,接着doInBackground()执行,在doInBackground()中调用 publishProgress(),publishProgress()触发onProgressUpdate(),doInBackground()执行完后再执行onPostExecute()。

当异步任务取消时,onCancelled()执行,onPostExecute()不会被调用。

AsyncTask的限制:
1,AsyncTask的对象必须在主线程中创建。

2,execute必须在UI线程中调用。

3,不要在程序中直接调用AsyncTask中的方法。

4,不能在doInBackground(Params… params)中更改UI组件的信息

5,一个AsyncTask对象只能执行一次,即只能调用一次execute()方法。否则会报运行时异常。

6,在 Android 1.6 之前,AsynTask是串行执行任务的,Android 1.6时AsynTask开始采用线程池处理并行任务,Android 3.0开始,为了避免AsynTask带来的并发错误,AsynTask 又采用一个线程池来串行执行任务。但是在Android 3.0之后可以通过AsynTask 的executeOnExecutor()方法来执行并发操作。

AsynTask的doInBackground()是一个抽象方法(继承时必须重写),onPreExecute()、onProgressUpdate()、onPostExecute()、onCancelled()的方法体都是空的,需要选择性的重写。publishProgress()是final修饰的,不能重写,只能去调用(在doInBackground()中调用)。

@MainThreadprotected void onPreExecute() {}@WorkerThreadprotected abstract Result doInBackground(Params... params); @WorkerThreadprotected final void publishProgress(Progress... values) {    if (!isCancelled()) {        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,                new AsyncTaskResult<Progress>(this, values)).sendToTarget();    }}@MainThreadprotected void onProgressUpdate(Progress... values) {}@MainThreadprotected void onPostExecute(Result result) {}@MainThreadprotected void onCancelled(Result result) {    onCancelled();}   @MainThreadprotected void onCancelled() {}

AsyncTask的初始状态为Status.PENDING(准备状态)

//初始状态为准备 private volatile Status mStatus = Status.PENDING;public enum Status {    /**     * 任务正在准备     * Indicates that the task has not been executed yet.     */    PENDING,    /**     * 任务正在运行     * Indicates that the task is running.     */    RUNNING,    /**     * 任务已经完成     * Indicates that {@link AsyncTask#onPostExecute} has finished.     */    FINISHED,}public final Status getStatus() {    return mStatus;}

以execute()作为入口来分析一下AsyncTask的执行流程

@MainThreadpublic final AsyncTask<Params, Progress, Result> execute(Params... params) {    return executeOnExecutor(sDefaultExecutor, params);}@MainThreadpublic 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)");        }    }    //任务状态修改为RUNNING(正在运行)    mStatus = Status.RUNNING;    //调用onPreExecute()    onPreExecute();    mWorker.mParams = params;    exec.execute(mFuture);    return this;}

{}HandlerThread

HandlerThread 继承了 Thread,是一个可以使用 Handler 的 Thread。它的实现就是在 run() 方法中通过 Looper.prepare() 来创建消息队列,并通过Looper.loop() 来开启消息循环。当不需要再使用HandlerThread 时,可以通过 HandlerThread 对象的 quit() 或者 quitSafely() 来终止线程的执行。

HandlerThread 在内部创建了消息队列,外界需要通过 Handler 的消息方式来通知过 HandlerThread 执行一个具体的任务。

HandlerThread 在IntentService中有具体的体现。

//HandlerThread的run()源码@Overridepublic void run() {    mTid = Process.myTid();    Looper.prepare();    synchronized (this) {        mLooper = Looper.myLooper();        notifyAll();    }    Process.setThreadPriority(mPriority);    onLooperPrepared();    Looper.loop();    mTid = -1;}

{}IntentService

IntentService 继承 Service 并且是一个抽象类。

IntentService可用于执行后台耗时任务,当任务执行完成后会自动停止。同时也是Service的原因。这导致它的优先级比单纯的线程要高很多,所以IntentService比较适合执行一些高优先级的后台任务,因为它的优先级高不容易被系统杀死。

//IntentService的onCreate()源码 @Overridepublic void onCreate() {   startService(Context, Intent)    super.onCreate();    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");    thread.start();    mServiceLooper = thread.getLooper();    mServiceHandler = new ServiceHandler(mServiceLooper);}

IntentService第一次启动时, onCreate()被调用,在onCreate()会创建HandlerThread,然后利用它的Looper来构造一个Handler对象mServiceHandler,这样通过mServiceHandler发送的消息最终都会在HandlerThread中执行,从这个角度来看,IntentService可以用于执行后台操作。

//IntentService的onStartCommand()源码 @Overridepublic int onStartCommand(Intent intent, int flags, int startId) {    onStart(intent, startId);    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;}//IntentService的onStart()源码 @Overridepublic void onStart(Intent intent, int startId) {    Message msg = mServiceHandler.obtainMessage();    msg.arg1 = startId;    msg.obj = intent;    mServiceHandler.sendMessage(msg);}

每次启动IntentService,它的onStartCommand()就会被调用一次,IntentService在onStartCommand()中处理每个后台任务的Intent。

onStartCommand()调用onStart(),在onStart()通过mServiceHandler发送一个消息,这个消息会在HandlerThread中处理。

mServiceHandler收到消息后,会将Intent对象传递给onHandleIntent(),注意这个Intent对象和外界startService(intent)中的Intent是一致的。通过这个Intent即可解析出外界startService(intent)传递的参数。通过这些参数可以区分具体的任务,这样onHandleIntent()就可以对不同的后台任务做处理了。

//IntentService的ServiceHandler类源码 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);    }}

当onHandleIntent()执行结束后,IntentService会通过stopSelf(msg.arg1)来尝试停止服务。

采用stopSelf(msg.arg1)而不是stopSelf()来停止服务,是因为stopSelf()会立刻停止服务,而这时可能还有其他的消息未处理,stopSelf(msg.arg1)则会等待所有的消息都处理完毕才停止服务。

stopSelf(msg.arg1)在尝试停止服务之前会判断最近启动服务的次数是否和startId相等,如果相等就立刻停止,不相等则不停止。

IntentService的onHandleIntent()需要我们在子类中实现,它的作用是从intent参数中区分具体的任务并执行这些任务。

如果目前只有一个后台任务,那么onHandleIntent()方法执行完这个任务,stopSelf(msg.arg1)就直接停止服务,
如果目前有多个后台任务,那么当onHandleIntent()方法执行完最后一个任务,stopSelf(msg.arg1)才会停止服务,

由于每执行一次后台任务就必须启动一次IntentService,而IntentService内部是通过消息的方式向HandlerThread请求执行任务,Handler中的Looper是顺序处理消息的,所以IntentService也是顺序执行后台任务的。当有多个后台任务同时存在时,这些后台任务会按照外界发起的顺序排队执行。

[]线程池

线程池的优点:

1,重用线程池中的线程,避免因为线程的创建和销毁带来的性能开销。

2,能有效控制线程池的最大并发数,避免大量的线程之间互相抢占系统资源而导致的阻塞现象。

3,能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能。

线程池来源于Executor接口,真正的线程实现为ThreadPoolExecutor,根据线程池的功能特征上来说,线程池主要可以分为4类 FixedThreadPool,CachedThreadPool,ScheduledThreadPool,SingleThreadExecutor,这4类可以通过Executors的工厂方法来得到。

{}ThreadPoolExecutor对象的创建

ThreadPoolExecutor mThreadPoolExecutor= new ThreadPoolExecutor(            int corePoolSize,            int maximumPoolSize,            long keepAliveTime,            TimeUnit unit,            BlockingQueue<Runnable> workQueue,            ThreadFactory threadFactory,            RejectedExecutionHandler handler)

corePoolSize参数:线程池的核心线程数,默认情况下,核心线程会在线程池中一直存活,即使他们处于闲置状态,如果将ThreadPoolExecutor的allowCoreThreadTimeOut()设置为true,那么闲置的核心线程在等待新任务到来时会有超时策略,这个时间间隔由keepAliveTime指定,当等待时间超过keepAliveTime指定的时长,核心线程就会停止。

maximumPoolSize参数:线程池所能容纳的最大线程数,当活动线程数达到这个数值后,后续的新任务会被阻塞。

keepAliveTime参数:非核心线程闲置时的超时时长,超过这个时长,非核心线程就会被回收,当ThreadPoolExecutor的allowCoreThreadTimeOut()设置为true,keepAliveTime同样会作用于核心线程,

unit参数:用于指定keepAliveTime参数的时间单位,这是一个枚举,常见的有TimeUnit.MILLISECONDS(毫秒),TimeUnit.SECONDS(秒), TimeUnit.MINUTES(分钟),

workQueue参数:线程池中的任务队列,通过线程池的execute()提交的Runnable对象会存储在这个参数中。

threadFactory参数:线程工厂,为线程池提供创建新线程的功能,ThreadFactory 是一个接口,它只有一个方法 newThread()。

handler参数:这个参数不常使用,当线程池无法执行新任务时,可能是由于任务队列已满或者是无法成功执行任务,这个时候ThreadPoolExecutor就会调用handler的rejectedExecution()来通知调用者。默认情况下rejectedExecution()会直接抛出一个RejectedExecutionException。ThreadPoolExecutor为RejectedExecutionHandler提供了几个可选值:CallerRunsPolicy,AbortPolicy,DiscardPolicy,DiscardOldestPolicy。其中AbortPolicy是默认值,它会直接抛出RejectedExecutionException。

{}ThreadPoolExecutor的执行任务规则

1,如果线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务。

2,如果线程池中的线程数量已经达到或者超过核心线程的数量,那么任务会插入到任务队列中排队等待执行。

3,如果无法将任务插入到任务队列中,这可能是由于任务队列已满,这时如果线程数量未达到线程池规定的最大值,那么会立刻启动一个非核心线程数来执行任务。

4,如果线程数量已经达到线程池规定的最大值,那么就拒绝执行任务。ThreadPoolExecutor会调用RejectedExecutionHandler的rejectedExecution()来通知调用者。

{}FixedThreadPool

FixedThreadPool是通过Executors的newFixedThreadPool()方法来创建的,它是线程数量固定的线程池,当线程处于空闲状态时,它们不会被回收,除非线程池被关闭了,当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来,

FixedThreadPool只有核心线程(核心线程数和容纳的最大线程数相等)并且这些核心线程不会被回收,这意味着它能够快速的响应外界请求。

ExecutorService fixedThreadPool =  Executors.newFixedThreadPool(int nThreads)public static ExecutorService newFixedThreadPool(int nThreads) {    return new ThreadPoolExecutor(        nThreads,         nThreads,        0L,         TimeUnit.MILLISECONDS,        new LinkedBlockingQueue< Runnable>());}

{}CachedThreadPool

CachedThreadPool是通过Executors的newCachedThreadPool()方法来创建的,它是一个线程数量不定的线程池。它只有非核心线程,并且最大线程数是一个很大的数(Integer.MAX_VALUE),实际上就相当于最大线程数可以任意大。

当线程池中的线程都处于活动状态时,线程池会创建新的线程来处理新任务,否则就会利用空闲的线程来处理新任务。线程池中的空闲线程都有超时机制,这个超时时长为60秒,超过60秒闲置线程就会被回收

CachedThreadPool主要用于执行大量的耗时较少的任务,当整个线程池都处于闲置状态时,线程池中的线程都会超时而被停止,这时CachedThreadPool中实际上是没有任何线程的。

ExecutorService cachedThreadPool= Executors.newCachedThreadPool()public static ExecutorService newCachedThreadPool() {    return new ThreadPoolExecutor(        0,         Integer.MAX_VALUE,        60L,         TimeUnit.SECONDS,        new SynchronousQueue<Runnable>());}

{}ScheduledThreadPool

ScheduledThreadPool是通过Executors的newScheduledThreadPool()方法来创建的,它的核心线程数量是固定的,而非核心线程数量是没有限制的,并且当非核心线程闲置时会被立即回收,

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

ExecutorService scheduledThreadPool =Executors.newScheduledThreadPool(int corePoolSize)public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {    return new ScheduledThreadPoolExecutor(corePoolSize);}public ScheduledThreadPoolExecutor(int corePoolSize) {    super(corePoolSize,            Integer.MAX_VALUE,            DEFAULT_KEEPALIVE_MILLIS,            MILLISECONDS,            new DelayedWorkQueue());}

{}SingleThreadExecutor

SingleThreadExecutor是通过Executors的newSingleThreadExecutor()方法来创建的,它只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行。

SingleThreadExecutor主要用于统一所有的外界任务到一个线程中,这使得在这些任务之间不需要处理线程同步的问题。

ExecutorService singleThreadExecutor= Executors.newSingleThreadExecutor()public static ExecutorService newSingleThreadExecutor() {    return new FinalizableDelegatedExecutorService        (new ThreadPoolExecutor(            1,             1,            0L,             TimeUnit.MILLISECONDS,            new LinkedBlockingQueue<Runnable>()));}

{}线程池的使用

Runnable command = new Runnable() {    @Override    public void run() {    }};ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);fixedThreadPool.execute(command);ExecutorService cachedThreadPool = Executors.newCachedThreadPool();cachedThreadPool.execute(command);ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(4);//2000ms后执行commandscheduledExecutor.schedule(command, 2000, TimeUnit.MILLISECONDS);//延时10ms后,每隔1000ms执行一次commandscheduledExecutor.scheduleAtFixedRate(command, 10, 1000, TimeUnit.MILLISECONDS);ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();singleThreadExecutor.execute(command);
0 0