内容来自《Android艺术开发探索》
线程
(1)AsyncTask
AsyncTask使用一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把后台的进度和最终结果传递给主线程并在主线程中更新UI。从实现上来说,AsyncTask封装了Thread和Handler,AsyncTask不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池。

AsyncTask是一个抽象的泛型类,它提供了Params、Progress和Result这三个泛型参数,Params表示参数的类型,Progress表示后台执行任务的进度,而Result表示后台任务返回的类型,如果AsyncTask不需要穿具体的参数,那么这三个泛型可以用Void来代替。

AsyncTask提供了4个方法,它们的含义如下所示。

a.onPreExecute(),在主线程中执行,在异步执行之前,此方法会被调用,一般可以用来做一些准备工作

b.doInBackground(Params… params),在线程池中执行,此方法用于执行异步任务,params参数表示的异步任务的输入参数。在此方法可以通过publishProgress方法来更新任务的进度,publishProgress方法会调用onProgressUpdate方法。另外doInBackground方法需要返回结果给onPostExecute。

c.onProgressUpdate(Progress… value), 在主线程中执行,当后台任务的执行进度发生改变时此方法会被调用。

d.onPostExecute(Result result),在主线程中执行,在异步任务执行之后,此方法会被调用,其中result参数是doInBackground的返回值。

上面这几个方法,onPreExecute先执行,接着是doInBackground,最后是onPostExecute。除了上述的四个方法以外,AsyncTask还提供了onCancelled()方法,它同样是在主线程中执行,当异步任务被取消的时候onCancelled()方法会被调用。下面一共一个典型的示例。

 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {     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));             // Escape early if cancel() is called             if (isCancelled()) break;         }         return totalSize;     }     protected void onProgressUpdate(Integer... progress) {         setProgressPercent(progress[0]);     }     protected void onPostExecute(Long result) {         showDialog("Downloaded " + result + " bytes");     } }

AsyncTask在具体的使用过程中也是有一些条件限制的,主要有如下几点:
a.AsyncTask的类必须在主线程中加载。
b.AsyncTask的对象必须在主线程中创建
c.execute方法必须在UI线程调用
d.不要在程序中直接调用onPreExecute、onPostExecute、doInBackground和onProgressUpdate方法
e.一个AsyncTask对象执行执行一次,即只能调用一次execute方法,否则会报异常
f.在1.6之前AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程里处理并行任务,再是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask有采用了一个线程来串行执行任务。尽管如此,在3.0以后的版本中,我们仍然可以用过AsyncTask的executeOnExecutor方法来并行的执行任务。

(2)HandlerThread
HandlerThread继承了Thread,它是一个可以使用Handler的Thread,它的实现也很简单,就是在run方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环,这样在实际的使用中就允许在HandlerThread中创建Handler了。

//创建一个HandlerThread,即创建了一个包含Looper的线程。HandlerThread handlerThread = new HandlerThread("com");//创建HandlerThread后一定要记得start()handlerThread.start(); //获取HandlerThread的LooperLooper looper = handlerThread.getLooper();//创建Handler,通过Looper初始化final Handler handler = new Handler(looper);

通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。
如果想让HandlerThread退出,则需要调用handlerThread.quit()或handlerThread.quitSafely();。

(4)IntentService
IntentService是一种特殊的Service,它继承了Service并且它是一个抽象类。IntentService可用于执行后台耗时的任务,当任务执行完它会自动停止,同时由于IntentService是服务的原因,这导致它的优先级比单纯的进程高跟多,所以IntentService比较适合执行一些高优先级的后台任务,因为它优先级高不容易被杀死。在实现上IntentService封装了HandlerThread和Handler。

线程池

使用线程池的好处:
a.重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销
b.能有效的控制线程池的最大并发数,避免大量的线程之间因为互相抢占系统资源而导致阻塞现象
c.能对线程池进行简单的管理,并提供定时执行以及指定间隔循环执行等功能
(1)ThreadPoolExecutor
ThreadPoolExecutor是线程池的真正实现,它的构造方法提供了一系列参数来配置线程池,这些参数会直接影响到线程池的功能特性,下面是ThreadPoolExecutor的一个比较常用的构造方法。

public ThreadPoolExecutor(int corePoolSize,                              int maximumPoolSize,                              long keepAliveTime,                              TimeUnit unit,                              BlockingQueue workQueue,                              ThreadFactory threadFactory

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是一个接口,它只有一个方法Thread newThread(Runnable r)。

ThreadPoolExecutor执行任务是大致遵循如下规则:

a.如果线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务
b.如果线程池中的线程属性已经到达或超过核心线程的数量,那么任务会被插入到任务队列中排队等待执行。
c.如果在步骤b中无法将任务插入到任务队列中,这个往往是由于任务队列已满,这个时候如果线程数量为达到线程的最大值,那么会立刻启动一个非核心线程来执行
d.如果步骤c中线程数量已经达到线程规定的最大值,那么就拒绝执行此任务,ThreadPoolExecutor会调用RejectedExecutionHandler handler的rejectedExecution方法来通知调用者

(2)线程池的分类

android中常见的四类具有不同功能特性的线程池,它们都直接或间接的通过配置ThreadPoolExecutor来实现自己的功能特性。

FixedThreadPool,通过Executors.newFixedThreadPool()方法来创建。它是一种线程数量固定的线程池,当线程处于空闲状态是,它们并不会回收,除非线程池被关闭了。当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来。由于FixedThreadPool只有核心线程并且这些核心线程不会被回收,这意味着它能够更加快速的相应外界的请求。方法的实现如下所示,可以发现FixedThreadPool中只有核心线程并且这些核心线程没有超时机制,另外任务队列也是没有大小限制的。

public static ExecutorService newFixedThreadPool(int nThreads) {    return new ThreadPoolExecutor(nThreads, nThreads,                                  0L, TimeUnit.MILLISECONDS,                                  new LinkedBlockingQueue());}

CachedThreadPool,通过Executors.newCachedThreadPool()方法创建。它是一种线程数量不定的线程池,它只有非核心线程,并且其最大值为Integer.MAX_VALUE。线程池中的空闲线程都有超时机制,这个超时时长为60秒,超过60秒闲置线程就会被回收和ThreadPoolExecutor不同的是,CachedThreadPool的任务队列其实相对与一个空集合,这个导致任何任务都会立即被执行,因为SynchronousQueue是无法插入任务的。从CachedThreadPool的特性来看,这类线程池比较比较适合执行大量的耗时较少的任务。当整个线程池都处于闲置状态时,线程池中的线程都会超时而被停止,这个时候CachedThreadPool之中实际上是没有任何线程的,它几乎是不占用任何系统资源的newCachedThreadPool如下所示

public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue());    }

ScheduledThreadPool,通过Executors.newScheduledThreadPool方法来创建。它的核心线程数量是固定的,而非核心线程数是没有限制的,并且当非核心线程闲置是会被立即回收。ScheduledThreadPool这类线程又要用于执行定时任务和具有固定周期的重复任务。newScheduledThreadPool方法的实现如下所示。

public ScheduledThreadPoolExecutor(int corePoolSize) {    super(corePoolSize, Integer.MAX_VALUE,          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,          new DelayedWorkQueue());}

SingleThreadExecutor,通过Executors.newSingleThreadExecutor方法来创建。这类线程池内部只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行。SingleThreadExecutor的意义在与统一所有外界的任务到一个线程中,这是的这些任务之间不需要处理线程同步问题newSingleThreadExecutor方法的实现如下所示。

public static ExecutorService newSingleThreadExecutor() {    return new FinalizableDelegatedExecutorService        (new ThreadPoolExecutor(1, 1,                                0L, TimeUnit.MILLISECONDS,                                new LinkedBlockingQueue()));}

更多相关文章

  1. Android:Activity与Fragment通信(99%)完美解决方案
  2. 第一行代码 Android读书笔记(四)
  3. [置顶] Android触摸事件分发
  4. DataBinding使用教程详解
  5. Android(安卓)面试总结
  6. 在Service中新开线程和直接新开线程的区别与意义
  7. 针对 CoordinatorLayout 及 Behavior 的一次细节较真
  8. Android(安卓)ListView理解之BaseAdapter
  9. 小记Activity生命周期(onCreate)

随机推荐

  1. PHP面试题汇总(附答案)
  2. PHP is_file、file_exists、is_dir总结
  3. php 创建目录的几种方法
  4. PHP跨域问题解决方案
  5. 深度解析Nginx下的PHP框架路由实现
  6. php查询数据库并输出乱码
  7. PHP生成有背景的二维码图片
  8. php关于日期时间的操作
  9. php策略模式和适配器模式的区别
  10. windows定时执行PHP文件