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