Android开发艺术探索 - 第11章 Android的线程和线程池

46 篇文章 0 订阅
39 篇文章 0 订阅

Android的主线程主要是运行四大组件以及处理其与用户的交互;而子线程用于执行耗时任务,如网络请求,I/O操作。

1.Android中的线程形态
  1. AsyncTask
    在线程池中执行后台任务,其封装了Thread和Handler,通过execute方法执行AsyncTask。关键方法:
    • onPreExecute:在执行execute方法的线程中运行,一般为主线程,用于执行在开始异步任务之前的一些准备工作。
    • doInBackground:在线程池中运行,用于执行异步任务。方法中通过publishProgress方法更新任务进度,进而调用到onProgressUpdate方法。此方法需要返回计算结果给onPostExecute。
    • onProgressUpdate:主线程中运行,异步任务更新进度时被回调。
    • onPostExecute:主线程中运行,异步任务执行完毕被回调。
    • onCancelled:主线程中运行,当异步任务被取消时被回调,此时onPostExecute不会被调用。

限制:
* AsyncTask的类必须要在主线程中加载。所以第一次访问AsyncTask时需要在主线程中进行,Android 4.1以上会自动完成这个过程,在ActivityThread的main方法中。
* AsyncTask的对象必须在主线程中创建。
* execute方法必须在UI线程调用。
* 不要直接调用AsyncTask的关键方法。
* 一个AsyncTask对象只能执行一次,即execute只能调用一次,否则会抛出异常。
* 可以通过exectueOnExecutor来指定线程池执行任务。

原理:
从execute方法开始。execute会使用默认的线程池,即SerialExecutor。一个进程中所有的AsyncTask都会在这个线程池中排队(static成员):

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

之后调用executeOnExecutor,先执行onPreExecute方法,然后线程池开始执行:

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
        Params... params) {
    ...
    mStatus = Status.RUNNING;

    onPreExecute();

    mWorker.mParams = params;
    exec.execute(mFuture);

    return this;
}

SerialExecutor的实现。在实例化AsyncTask的时候,会创建一个FutureTask对象,该类是一个并发类,充当了Runnable的作用,其中会包含execute传入的参数。当线程池开始执行,首先将当前的FutureTask对象插入到任务队列中,如果当前没有正在活动的任务,则调用scheduleNext方法执行下一个任务;同时一个任务执行完毕,也会调用scheduleNext方法执行下一个任务:

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);
        }
    }
}

scheduleNext方法则通过另一个线程池,THREAD_POOL_EXECUTOR去具体执行任务,该线程池是个并发线程池。默认情况下,AsyncTask会通过SERIAL_EXECUTOR接收Runnable,串行的每次执行一个,而具体的执行任务交由THREAD_POOL_EXECUTOR;可以让AsyncTask并发的去执行Runnable,只要在其execute方法中,直接指定THREAD_POOL_EXECUTOR这个线程池就可以了。
当任务开始执行,会调用FutureTask的run方法。在实例化AsyncTask的时候,会创建一个WorkerRunnable,同时绑定到FutureTask上,FutureTask的run方法会调用WorkerRunnable的call方法,此时doInBackground方法便会被执行:

    public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return result;
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            ...
        };
    }

doInBackground执行完毕,会调用postResult发送出结果,其任务就是通过AsyncTask内部的Handler发送一个msg:

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

该Handler在创建时,Looper指定为main looper,保证其回调发生在主线程。当任务处理完成,Handler在主线程中执行AsyncTask#finish方法,当更新进度则回调AsyncTask#onProgressUpdate方法:

    private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }

        @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;
            }
        }
    }

finish方法中,则根据是否AsyncTask是否被取消了,去回调onCancel或者onPostExecute:

private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}
  1. HandlerThread
    继承自Thread,并在run方法中创建消息队列和开启了消息循环,之后便可直接通过该Thread创建相应的Handler去执行任务。其run方法:
@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}
  1. IntentService
    继承自Service,内部使用了HandlerThread和Handler来实现,任务在子线程中的串行执行。onCreate方法中创建HandlerThread的实例,并通过其Looper创建Handler:
@Override
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);
}

而Handler的具体实现,是回调onHandleIntent方法,将具体的任务实现交由其子类,任务执行完毕后调用stopSelf尝试停止service。所有任务完成后,service销毁:

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);
    }
}

client使用时,直接startService,IntentService#onStart方法中就会通过Handler将Intent包裹为msg发出,等待Looper去执行:

@Override
public void onStart(@Nullable Intent intent, int startId) {
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}
2.Android中的线程池

优点:

  • 重用线程池中的线程,减少创建和销毁带来的性能开销;
  • 能控制最大并发数,避免大量线程抢占资源导致阻塞;
  • 能对线程进行简单的管理,提供定时执行和间隔循环执行等功能。

Android中的线程池为接口Executor,具体实现类为ThreadPoolExecutor,通过为其配置不同的参数,可以创建不同的线程池。

  1. ThreadPoolExecutor
    常用的构造方法:
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory) {
* corePoolSize:核心线程数。默认情况下,核心线程会在线程池中一直存活,即使处于闲置状态。
* maximumPoolSize:最大线程数。包括了核心线程和非核心线程。
* keepAliveTime:非核心线程闲置的超时时间,超过这个时间就就会被回收。当把allowCoreThreadTimeOut设置为true,同时也会作用于核心线程的。
* unit:keepAliveTime的时间单位。
* workQueue:线程池中的任务队列,通过execute方法提交的Runnable会添加到这里。
* threadFactory:创建线程时使用的工具类。
* RejectedExecutionHandler类型的不常用参数,用于指定,当无法执行新任务时,线程池会回调该handler的rejectedExecution方法,默认实现是直接抛出一个RejectedExecutionHaException异常。

ThreadPoolExecutor执行任务的规则:
1. 如果线程池中的核心线程数未达到上限,则直接启动一个核心线程去执行;
2. 如果核心线程数已达上限,则将任务插入到队列中排队;
3. 如果队列也满了,则尝试创建非核心线程去执行;
4. 如果总的线程数已经达到了上限,此时已经无法执行任务,此时便会调用RejectedExecutionHandler#rejectedExecution方法,通知调用者。

ThreadPoolExecutor在AsyncTask中的创建示例:
```
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;

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 BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(128);

/**
 * An {@link Executor} that can be used to execute tasks in parallel.
 */
public static final Executor THREAD_POOL_EXECUTOR;

static {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
            sPoolWorkQueue, sThreadFactory);
    threadPoolExecutor.allowCoreThreadTimeOut(true);
    THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
```
* 核心线程数为2~4个
* 最大线程数为2*Cpu核心数+1
* 核心线程有闲置超时
* 任务队列容量为128
  1. 四类线程池
    四类线程池都是通过Executors的静态方法进行创建。
    • FixedThreadPool:具有固定的核心线程,且不会被回收,当所有的核心线程处于活跃状态,新任务则排队等待。能够更快的响应外界的需求。
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    
    • CachedThreadPool:没有核心线程,具有无限数量的非核心进程,且线程闲置超时会被回收;其任务队列相当于空集,所以不会缓存任何任务,有新任务便会马上执行。适合执行大量且耗时少的任务。同时因为闲置时线程会被回收,所以其闲置状态几乎不占用系统资源。
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    
    • ScheduledThreadPool:具有固定数量的核心线程和无限的非核心线程,非核心线程闲置超时会被回收。用于执行定时任务和周期性任务。
        public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
            return new ScheduledThreadPoolExecutor(corePoolSize);
        }
    
        // ScheduledThreadPoolExecutor.java
    
        private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
    
        public ScheduledThreadPoolExecutor(int corePoolSize) {
            super(corePoolSize, Integer.MAX_VALUE,
                  DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
                  new DelayedWorkQueue());
        }
    
    • SingleThreadPool:只有一个核心线程,所有的任务按顺序执行。
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值