Android沿用了Java的线程模型,线程分为主线程和子线程,主线程主要负责处理和界面相关的事情,而子线程则主要用于执行耗时操作,其中主线程也叫UI线程。
除了Thread外,Android还提供AsyncTask、IntentService和HandlerThread这些特殊的线程,尽管他们的表现形式有别于传统的线程,但是它们本质仍然是传统的线程。AsyncTask底层用到了线程池,IntentService和HandlerThread底层则直接用到了线程。
● AsyncTask——封装了线程池和Handler,它主要是为了方便开发者在子线程中更新UI;
● IntentService——是一种服务,内部采用HandlerThread来执行任务,系统封装使其更方便执行后台任务;
● HandlerThread——一种具有消息循环的线程,在它内部可以使用Handler。
AsyncTask
AsyncTask是一种轻量级的异步任务类,
HandlerThread
HandlerThread继承了Thread,它是一种可以使用Handler的Thread,实现方式就是在run方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环,其run方法如下:
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
普通Thread一般执行耗时操作,而HanderThread不同之处在于,内部创建了消息队列,外界可以通过handler的消息方式来通知HandlerThread执行一个具体的任务。具体的使用场景是就是IntentService。
由于HandlerThread的run是一个无限循环,因此当明确不需要HandlerThread时,可以通过它的quit或者quitSafely方法来终止制线程的执行。
IntentService
IntentService是一种特殊的Service,它继承了Service并且它是一个抽象类,同时IntentService是服务的原因,这导致它的优先级比单纯的线程要高得多,所以它比较适合执行一些高优先级的后台任务,不容易被系统杀死,IntentService可用于执行后台耗时的任务,当任务执行后它会自动停止。
在实现上,IntentService封装了HandlerThread和Handler,从它的onCreate方法中可以看出:
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService["+ mName +"]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
这样mServiceHandler发送的消息最终都会在HandlerThread中执行,IntentService在onStartCommand方法中处理每个后台任务的Intent,onStartCommand调用了onStart方法,看下onStart的具体实现
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
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);
}
}
IntentService的onHandleIntent方法是一个抽象方法,作用是从Intent参数中区分具体的任务并执行这些任务。
如果目前只存在一个后台任务,那么onHandleIntent执行完这个任务后,stopSelf(int startId)就会直接停止服务,如果目前存在多个后台任务,那么onHandleIntent执行完最后一个任务stopSelf才停止服务,stopSelf(int startId)在尝试停止服务之前会判断最近启动服务的次数是否和startId相等,如果相等就立刻停止服务。
IntentService使用示例如下:
public class LocalIntentService extends IntentService {
private static final String TAG = LocalIntentService.class.getSimpleName();
public LocalIntentService() {
super(TAG);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
String action = intent.getStringExtra("task_action");
Log.d(TAG, "receive task: " + action);
SystemClock.sleep(3000);
if ("com.gomez.action.task1".equals(action)) {
Log.d(TAG, "handle task: " + action);
}
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: service destroyed");
}
}
通过示例可以发现IntentService是按外界顺序执行后台任务的,因为Handler中的Looper是顺序处理消息的。
线程池的分类
常用的4类线程池分别为FixThreadPool、CachedThreadPool、ScheduleThreadPool和SingleThreadExecutor。
FixThreadPool
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>());
}
①线程数量可以任意大
②没有核心线程,闲置线程60秒会被回收
③任务队列无法插入任务
ScheduleThreadPool
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
new DelayedWorkQueue());
}
①核心线程是固定的,非核心线程数没有限制
②非核心线程闲置会被马上回收
③任务队列大小没有限制
SingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
①只有1个核心线程,没有非核心线程
②线程不会被回收
具体使用示例如下:
Runnable task = new Runnable() {
@Override
public void run() {
SystemClock.sleep(2000);
}
};
ExecutorService fixThreadPool = Executors.newFixedThreadPool(4);
fixThreadPool.execute(task);
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(task);
ScheduledExecutorService scheduleThreadPool = Executors.newScheduledThreadPool(4);
//2s后执行task
scheduleThreadPool.schedule(task, 2000, TimeUnit.MILLISECONDS);
//延时10ms后执行,每隔1s执行一次task
scheduleThreadPool.scheduleAtFixedRate(task,10, 1000, TimeUnit.MILLISECONDS);
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
singleThreadExecutor.execute(task);