Android线程

Android的线程形式主要有四种

  1. Thread+Handler
  2. AsyncTask
  3. HandlerThread
  4. IntentService
对于第一种和第二种,已分别在Android的消息机制、Android线程之AsyncTask使用与原理分析两文中进行介绍,下面介绍第3种和第4种。

HandlerThread

HandlerThread继承了Thread,它是一种可以使用Handler的Thread,它通过在run方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环,这样在实际的使用中就允许在HandlerThread中创建Handler了。
public class HandlerThread extends Thread {}
HandlerThread的run方法如下:
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
HandlerThread与普通Thread不同之处在于HandlerThread在内部创建了一个消息队列,外界需要通过通过Handler的消息方式来通知HandlerThread去执行一个具体的任务。
HandlerThread的具体使用场景有IntentService,由于HandlerThread的run()方法是一个无限循环,因此当不需要使用HandlerThread的时候,可以通过他的quit或者quitSafety方法来终止线程循环

IntentService

IntentService 是继承自 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,当任务执行完后,IntentService 会自动停止。 如果启动 IntentService 多次,那么每一个耗时操作会以工作队列的方式在 IntentService 的 onHandleIntent 回调方法中执行,依次去执行,执行完自动结束。
同时由于IntentService是服务的原因,这导致它的优先级比单纯的线程要高很多,不容易被系统杀死,所以IntentService比较适合执行一些高优先级的后台任务。
public abstract class IntentService extends Service
在实现上IntentService封装了HandlerThread和Handler,这一点体现在它的onCreate()方法上
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();

mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
IntentService第一次启动时,它会创建一个HandlerThread,然后使用它的Looper来构造一个Handler对象mServiceHandler ,这样通过mServiceHandler发送的消息最终都会在HandlerThread中执行,从这个角度看,IntentService也适用于执行后台任务。

Android线程池

线程池的好处:
  1. 重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销。
  2. 能有效控制线程池的最大并发数,避免大量的线程之间互相因抢占系统资源而导致的阻塞现象。
  3. 能够对线程进行简单的管理,并提供定制执行以及指定间隔循环执行等功能。
Android中的线程池的概念来源于Java中的Executor,Executor是一个接口,真正的线程池的实现为ThreadPoolExecutor。ThreadPoolExecutor提供了一系列的参数来配置线程池,通过不同的参数可以配置不同的线程池。

ThreadPoolExecutor

ThreadPoolExecutor是线程池的真正实现,我们通过ThreadPoolExecutor的构造函数来配置特定的线程池,其构造方法如下
public ThreadPoolExecutor(int corePoolSize,//核心线程数,默认情况会一直存活
int maximumPoolSize,//线程池所能容纳的最大线程数,当达到这个数后,后续任务会被阻塞
long keepAliveTime,//非核心线程闲置时的超时时长,超过时间会被回收
TimeUnit unit,//用于指定超时时长的单位,枚举
BlockingQueue<Runnable> workQueue) //线程池中的任务队列,通过线程池的execu方法提交的runnable对象会存储在这个参数中
ThreadFactory threadFactory){//线程工程,为线程池提供创建新线程的功能
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);}
注意:当allowCoreThreadTimeOut属性被设置为true的时候,核心线程和非核心线程一样在闲置时有超时策略

ThreadPoolExecutor执行任务时大致遵循如下规则:
  1. 如果线程池的线程数量未达到核心线程数量,那么会直接启动一个核心线程来执行任务。
  2. 如果线程池中的线程数量已经达到或者超过核心线程的数量,那么任务会被插入到任务队列中等待排队执行。
  3. 如果再步骤2中无法将任务插入到任务队列中,那么这往往是由于任务队列已满,这时候如果线程数量未达到线程池规定的最大值,那么会立刻启动一个非核心线程来执行任务。
  4. 如果步骤3中线程数量已经达到了线程池规定的最大值,那么久拒绝执行此任务。ThreadPoolExecutor会调用RejectedExecutionHandler的rejectedExecution方法来通知调用者。

ThreadPoolExecutor参数的配置在AsyncTask中有明显体现,下面是AsyncTask中的线程池的配置情况
//CPU核心数
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//核心线程数 = CPU核心数 -1 与 4 中取一个最小值 这个最小值与2之间去最大值,最终核心线程数的范围为【2,5】 private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
//线程池最大线程数 = CPU核心数的2倍 + 1
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//超时设置为30S
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);

public static final Executor THREAD_POOL_EXECUTOR;

static {
//默认超时单位为秒,TimeUnit.SECONDS
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
//核心线程有超时机制
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}

线程池的分类

下面介绍Android中最常见的4类具有不同功能特性的线程池,他们都是通过直接或间接地配置ThreadPoolExecutor来实现自己的功能特性。

1. FixThreadPool

通过Executors的newFixedThreadPool方法来创建。它是一种线程数量固定的线程池,当线程处于空闲状态时,他们并不会被回收,除非线程池被关闭了。它只有核心线程,没有非核心线程。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}

2. CachedThreadPool

通过Executors的newCachedThreadPool方法来创建。它是一种线程数量不定的线程池,它只有非核心线程,并且最大值是Integer.MAX_VALUE,相当于可以任意大。 当有新任务的时候,有空闲线程就会调用空闲线程执行,没空闲线程就会创建新的线程,超时机制为60S。 它适合执行大量耗时较少的任务。 当整个线程池都处于闲置状态时,线程池中的所有线程都会因为超时而被停止,这时候线程池里没有任何线程,几乎不占用任何系统资源。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}

3. ScheduledThreadPool

通过Executors的newScheduledThreadPool方法来创建。它的核心线程数是固定的,而非核心线程数是没有限制的,并且当非核心线程闲置时会被立刻回收。
ScheduledThreadPool这类线程池主要用于执行定时任务和具有固定周期的重复任务。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}

4. SingleThreadExecutor

通过Executors的newSingleThreadExecutor方法来创建。它内部只有1个核心线程,它确保所有的任务都在同一个线程中按顺序执行。它的意义在于统一所有外界任务到一个线程中,从而使这些任务之间不需要处理线程同步问题。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}


延伸阅读:深入理解Java之线程池




更多相关文章

  1. Android多线程下载远程图片【转】
  2. 跟核心虚拟机Dalvik说再见 Android Runtime(ART)登场
  3. Android核心分析 之十-------Android GWES之基本原理篇
  4. Android学习笔记(三一):线程:Message和Runnable
  5. android多线程数据存储 - ThreadLocal的工作原理
  6. java基础---多线程---java内存模型
  7. java 使用Callable和Future返回线程执行的结果
  8. Java多线程聊天对话框
  9. Android 多线程下载文件原理霸气解析介绍 (完结版)-----greendao

随机推荐

  1. Android 开发入门
  2. android横屏竖屏处理
  3. Android图案密码,手势锁源码解析
  4. Android(安卓)文本阅读以及TextView指定
  5. Android UI开发第九篇——SlidingDrawer
  6. Android: 你必须掌握的Android命令
  7. android Spinner和数值选择器使用demo
  8. android经典DEMO
  9. android中Invalidate和postInvalidate的
  10. android 不销毁当前activity,返回上一层,亲