一、概述
Android 的線程分主線程和子線程,主線程主要處理界面相關(guān)的事情,而子線程往往用于執(zhí)行耗時(shí)操作。Android 中扮演子線程角色的有:AsyncTask、IntentService、HandlerThread。AsyncTask 封裝了線程池和 Handler,主要用于在子線程中更新UI。 HandlerThread 是一種具有消息循環(huán)的線程,在它的內(nèi)部可以使用 Handler。IntentService 是一個(gè) Service,系統(tǒng)對(duì)其進(jìn)行了封裝使其可以方便地執(zhí)行后臺(tái)任務(wù),執(zhí)行完任務(wù)后自動(dòng)調(diào)用 onDestroy()
退出。它是一個(gè) Service,因而在執(zhí)行后臺(tái)任務(wù)的時(shí)候不容易被系統(tǒng)殺死。
二、AsyncTask
AsyncTask 是一種輕量級(jí)的異步任務(wù)類,它可以在線程池中執(zhí)行后臺(tái)任務(wù),然后在主線程中回調(diào)執(zhí)行的進(jìn)度以及最終結(jié)果,從而更新 UI。其實(shí),AsyncTask 內(nèi)部封裝了 Thread 和 Handler。
ASyncTask 是一個(gè)抽象類。
public abstract class AsyncTask<Params,Progress,Result>
主要有 4 個(gè)核心的方法:
onPreExecute():在主線程執(zhí)行,在異步任務(wù)執(zhí)行之前的準(zhǔn)備工作,比如:提示 Loading
doInBackground(Params... params):在線程池中執(zhí)行,此方法用于執(zhí)行異步任務(wù),params 表示異步任務(wù)的輸入?yún)?shù)。
onProgressUpdated(Progress... value):在主線層中執(zhí)行,當(dāng)后臺(tái)任務(wù)的進(jìn)度發(fā)生改變時(shí)此方法被調(diào)用。
onPostExecute(Result result):在主線程執(zhí)行,在異步任務(wù)執(zhí)行完成后回調(diào)此方法。
onCancelled():在主線程執(zhí)行,當(dāng)異步任務(wù)被取消時(shí)會(huì)回調(diào)此方法。
舉個(gè)栗子:
class DownloadTask extends AsyncTask<URL,Integer,Long>{
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Long doInBackground(URL... urls) {
return null;
}
@Override
protected void onPostExecute(Long aLong) {
super.onPostExecute(aLong);
}
@Override
protected void onCancelled() {
super.onCancelled();
}
}
new DownloadTask().execute(url1,url2,url3);
劃重點(diǎn)來啦 !!!
1. AsyncTask 的類必須在主線程中加載,不過這個(gè)在 Android 4.1 及以上版本已經(jīng)在 ActivityThread 中初始化了。
2. AsyncTask 對(duì)象必須在主線程中創(chuàng)建。
3.
execute()
必須在 UI 線程中調(diào)用。4. 不要在程序中直接調(diào)用
onPreExcute()
、doInBackground()
、onPostExecute()
和onProgressUpdate()
。5. 一個(gè) AsyncTask 對(duì)象只能執(zhí)行一次,即只能調(diào)用一次
execute()
,否則會(huì)報(bào)運(yùn)行異常。6. 可以通過
executeOnExecutor()
來并行執(zhí)行任務(wù)。
三、HandlerThread
HandlerThread 繼承 Thread,它封裝有 Looper 和 MessageQueue,可以綁定 Handler,從而實(shí)現(xiàn)線程間通信/異步消息處理機(jī)制。
舉個(gè)栗子
/**
* 使用 HandlerThread
*/
public class HandlerThreadActivity extends AppCompatActivity {
private TextView mTvServiceInfo;
private HandlerThread mCheckMsgThread;
//HandlerThread 的 handler
private Handler mCheckMsgHandler;
private boolean isUpdateInfo;
private static final int MSG_UPDATE_INFO = 0x110;
//與UI線程管理的handler
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread);
//創(chuàng)建后臺(tái)線程
initBackThread();
mTvServiceInfo = findViewById(R.id.id_textview);
}
@Override
protected void onResume() {
super.onResume();
//開始查詢
isUpdateInfo = true;
mCheckMsgHandler.sendEmptyMessage(MSG_UPDATE_INFO);
}
@Override
protected void onPause() {
super.onPause();
//停止查詢
isUpdateInfo = false;
mCheckMsgHandler.removeMessages(MSG_UPDATE_INFO);
}
private void initBackThread() {
mCheckMsgThread = new HandlerThread("check-message-coming");
mCheckMsgThread.start();
//綁定 HandlerThread 的 Looper
mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
checkForUpdate();
if (isUpdateInfo) {
//循環(huán)執(zhí)行 HandlerThread Handler 的 handleMessage()
mCheckMsgHandler.sendEmptyMessageDelayed(MSG_UPDATE_INFO, 1000);
}
}
};
}
/**
* 模擬從服務(wù)器解析數(shù)據(jù)
*/
private void checkForUpdate() {
try {
//模擬耗時(shí)
Thread.sleep(1000);
//切換回主線程
mHandler.post(new Runnable() {
@Override
public void run() {
String result = "實(shí)時(shí)更新中,當(dāng)前大盤指數(shù):<font color='red'>%d</font>";
result = String.format(result, (int) (Math.random() * 3000 + 1000));
mTvServiceInfo.setText(Html.fromHtml(result));
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//釋放資源
mCheckMsgThread.quit();
}
}
這個(gè)栗子里面通過 HandlerThread 線程的 Handler 來通知 UI 線程的 Handler 來更新 UI,同時(shí)在 handleMessage() 方法中循環(huán)執(zhí)行 HandlerThread 的方法,這個(gè)也是一種定時(shí)循環(huán)執(zhí)行任務(wù)的方法。
源碼分析:
/**
* Handy class for starting a new thread that has a looper. The looper can then be
* used to create handler classes. Note that start() must still be called.
*/
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
//內(nèi)部有一個(gè) Handler 成員變量
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
}
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
我們仔細(xì)看看 run()
,這里面調(diào)用了 Looper.prepare()
,Loop.loop()
。Looper.prepare()
中創(chuàng)建了一個(gè) Looper 對(duì)象,并且把該對(duì)象放到了該線程范圍內(nèi)的變量中(sThreadLocal),在 Looper 對(duì)象的構(gòu)造過程中,初始化了一個(gè) MessageQueue ,作為該 Looper 對(duì)象成員變量。Looper.loop()
就不斷地循環(huán)從 MessageQueue 中取消息處理了,當(dāng)沒有消息的時(shí)候會(huì)阻塞,有消息的到來的時(shí)候會(huì)喚醒。
如果我們不想自己初始化 HandlerThread 的 Handler 對(duì)象,可以直接使用 HandlerThread 里面的 Handler,使用的時(shí)候就只能用 post(Runnable r)
,因?yàn)?HandlerThread 的 Handler 沒有派生子類,只能使用 Message.callback 來執(zhí)行任務(wù)。
四、IntentService
IntentService 是一種特殊的 Service,它繼承了 Service,并且是一個(gè)抽象類,子類必須實(shí)現(xiàn) onHandleIntent()
才可以使用。IntentService 可用于執(zhí)行后臺(tái)任務(wù),我們可以通過 startService(Intent)
來提交請(qǐng)求,該Service會(huì)在需要的時(shí)候創(chuàng)建,當(dāng)完成所有的任務(wù)以后自己關(guān)閉,且請(qǐng)求是在工作線程處理的。而且由于它是 Service,比單純的后臺(tái)線程優(yōu)先級(jí)高,不容易被系統(tǒng)殺死。
優(yōu)點(diǎn):
1.不需要自己去 new Thread
2.不需要考慮在什么時(shí)候關(guān)閉該 Service
舉個(gè)栗子
使用 IntentService 上傳照片
public class UploadImgService extends IntentService {
private static final String ACTION_UPLOAD_IMG = "com.zhy.blogcodes.intentservice.action.UPLOAD_IMAGE";
public static final String EXTRA_IMG_PATH = "com.zhy.blogcodes.intentservice.extra.IMG_PATH";
/**
* 外部調(diào)用開啟任務(wù)
* @param context
* @param path
*/
public static void startUploadImg(Context context, String path) {
Intent intent = new Intent(context, UploadImgService.class);
intent.setAction(ACTION_UPLOAD_IMG);
intent.putExtra(EXTRA_IMG_PATH, path);
context.startService(intent);
}
public UploadImgService() {
super("UploadImgService");
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_UPLOAD_IMG.equals(action)) {
final String path = intent.getStringExtra(EXTRA_IMG_PATH);
handleUploadImg(path);
}
}
}
private void handleUploadImg(String path) {
try {
//模擬上傳耗時(shí)
Thread.sleep(3000);
Intent intent = new Intent(MainActivity.UPLOAD_RESULT);
intent.putExtra(EXTRA_IMG_PATH, path);
//通過廣播通知 UI 線程
sendBroadcast(intent);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void onCreate() {
super.onCreate();
Log.e("TAG","onCreate");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e("TAG","onBind");
return null;
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.e("TAG","onSatrtCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Log.e("TAG","onSatrt");
super.onStart(intent, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e("TAG","onDestroy");
}
}
上面的代碼主要就是繼承IntentService,然后復(fù)寫onHandleIntent方法,根據(jù)傳入的intent來選擇具體的操作。
運(yùn)行 Log:
04-16 07:56:59.894 19936-19936/com.innovator.intentservicetest E/TAG: onCreate
onSatrtCommand
onSatrt
04-16 07:57:00.500 19936-19936/com.innovator.intentservicetest E/TAG: onSatrtCommand
onSatrt
04-16 07:57:00.774 19936-19936/com.innovator.intentservicetest E/TAG: onSatrtCommand
onSatrt
04-16 07:57:01.788 19936-19936/com.innovator.intentservicetest E/TAG: onSatrtCommand
onSatrt
04-16 07:57:01.965 19936-19936/com.innovator.intentservicetest E/TAG: onSatrtCommand
onSatrt
通過 startUploadImg(Context context, String path)
來創(chuàng)建多個(gè)任務(wù),可以看到 onCreate()
只調(diào)用了一次,onStartCommand()
和 onStart()
會(huì)回調(diào)多次。
劃重點(diǎn)啦 !!!
源碼解析:
package android.app;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
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);
}
}
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
protected abstract void onHandleIntent(Intent intent);
}
可以看到它在 onCreate()
里面初始化了一個(gè) HandlerThread,同時(shí)實(shí)例化了一個(gè)綁定該 HandlerThread 的 Handler。當(dāng)任務(wù)開始的時(shí)候,會(huì)回調(diào) onStartCommand()
,即回調(diào) onStart()
,在 onStart()
中可以看到這個(gè) Handler 發(fā)送了一條消息給自己,于是就會(huì)調(diào)用自己的處理方法,最后調(diào)用 onHandleIntent((Intent)msg.obj)
方法,所以我們?cè)谑褂?IntentService 的時(shí)候需要重寫 onHandleIntent((Intent)msg.obj)
。
而且,由于 HandlerThread 是串行執(zhí)行任務(wù)的,所以 IntentService 也是串行執(zhí)行任務(wù)的,執(zhí)行完成后會(huì)調(diào)用 stopSelf(msg.arg1);
判斷是否銷毀該 Service(stopSelf(msg.arg1);
會(huì)等待所有消息都處理完畢才會(huì)終止服務(wù))。所以當(dāng)任務(wù)完成,銷毀 Service 回調(diào) onDestory()
時(shí),源碼里面會(huì)釋放了我們的 Looper: mServiceLooper.quit()
。
五、線程池
使用線程池有幾個(gè)好處:
1.重用線程池的線程,避免為線程的創(chuàng)建和銷毀所帶來的性能開銷
2.能有效控制線程池的最大并發(fā)數(shù),避免大量線程之間因互相搶占資源而導(dǎo)致的阻塞現(xiàn)象
3.能夠?qū)€程進(jìn)行簡(jiǎn)單的管理,并提供定時(shí)執(zhí)行以及指定間隔循環(huán)執(zhí)行等功能。
5.1 ThreadPoolExecutor
ThreadPoolExecutor 是線程池的真正實(shí)現(xiàn),它的構(gòu)造方法為:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
corePoolSize:線程池的核心線程數(shù),默認(rèn)情況下,核心線程會(huì)在線程池一直存活,即使它們處于閑置的狀態(tài)。如果將 ThreadPoolExecutor 的
allowCoreThreadTimeOut
屬性為 true,那么閑置的核心線程在等待新任務(wù)到來的時(shí)候會(huì)有超時(shí)策略,這個(gè)時(shí)間間隔超過keepAliveTime
后,核心線程也會(huì)被終止。maximumPoolSize:線程池所能容納的最大線程數(shù)。當(dāng)活動(dòng)線程數(shù)達(dá)到這個(gè)數(shù)值后,后續(xù)的新任務(wù)會(huì)被阻塞。
keepAliveTime:非核心線程閑置時(shí)的超時(shí)時(shí)長(zhǎng),超過這個(gè)時(shí)長(zhǎng),非核心線程就會(huì)被回收。
unit:超時(shí)時(shí)長(zhǎng)單位:毫秒,秒,分
workQueue:線程池的任務(wù)隊(duì)列,通過線程池的
execute()
提交的 Runnable 對(duì)象就存儲(chǔ)在這個(gè)隊(duì)列中。threadFactory:線程工廠,為線程池提供創(chuàng)造新線程的功能。
ThreadPoolExecutor 執(zhí)行任務(wù)時(shí)的規(guī)則:
1.如果線程池中的線程數(shù)量未達(dá)到核心線程的數(shù)量,那么會(huì)直接啟動(dòng)一個(gè)核心線程來執(zhí)行任務(wù)
2.如果線程池中的線程數(shù)量已經(jīng)達(dá)到或者超過核心線程數(shù)量,那么任務(wù)就會(huì)被插入到任務(wù)隊(duì)列中排隊(duì)等待執(zhí)行
3.如果步驟2中的任務(wù)無法插到任務(wù)隊(duì)列,這往往是由于任務(wù)隊(duì)列已滿,這時(shí)如果線程數(shù)量未達(dá)到線程池的最大值,那么就會(huì)立刻啟動(dòng)一個(gè)非核心線程來執(zhí)行任務(wù)。
4.如果步驟3中線程數(shù)量已經(jīng)達(dá)到線程池規(guī)定的最大值,那么就會(huì)拒絕執(zhí)行這項(xiàng)任務(wù),ThreadPoolExecutor 就會(huì)調(diào)用 RejectedExecutionHandler 的
rejectExecution()
來通知調(diào)用方。
5.2 線程池分類
-
1.FixedThreadPool:一種線程數(shù)量固定的線程池,核心線程數(shù)就是線程池能容納的最大線程數(shù)。所以當(dāng)線程處于空閑狀態(tài)時(shí),它們并不會(huì)回收,除非線程池被關(guān)閉了。當(dāng)所有線程都處于活動(dòng)狀態(tài)時(shí),新任務(wù)都會(huì)處于等待狀態(tài),直到有空閑的線程。因?yàn)?FixedThreadPool 只有核心線程并且這些核心線程不會(huì)被回收,這就意味著它能更加快速地響應(yīng)外界的請(qǐng)求。FixedThreadPool 的任務(wù)隊(duì)列沒有大小限制。
構(gòu)造方法:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
使用方法:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
fixedThreadPool.execute(Runnable r);
-
CachedThreadPool:一種線程數(shù)量不定的線程池,只有非核心線程,并且最大線程數(shù)為 Interger.MAX_VALUE。當(dāng)線程池中的線程都處于活動(dòng)狀態(tài)時(shí),線程池會(huì)創(chuàng)建新的線程來處理任務(wù),否則就會(huì)利用空閑線程來處理新任務(wù)。線程池中的空閑線程都有超時(shí)機(jī)制,超時(shí)時(shí)長(zhǎng)為 60s,超過 60s 就會(huì)被回收。它比較適合執(zhí)行大量的耗時(shí)較少的任務(wù)。
構(gòu)造方法:
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
使用方法:
ExecutorService cacheThreadPool = Executors.newCachedThreadPool();
cacheThreadPool.execute(Runnable r);
-
ScheduledThreadPool:核心線程數(shù)量固定,線程池能容納的最大線程數(shù)沒有限制,并且當(dāng)非核心線程閑置時(shí)會(huì)被立即回收。主要用于執(zhí)行定時(shí)任務(wù)和具有固定周期的重復(fù)任務(wù)。
構(gòu)造方法:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue()); }
使用方法:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
//延遲2秒后執(zhí)行該任務(wù)
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
}
}, 2, TimeUnit.SECONDS);
//延遲1秒后,每隔2秒執(zhí)行一次該任務(wù)
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
}
}, 1, 2, TimeUnit.SECONDS);
-
SingleThreadExecutor:這類線程池內(nèi)部只有一個(gè)核心線程,它確保所有任務(wù)都在同一個(gè)線程中按順序執(zhí)行。意義就是統(tǒng)一所有外界的任務(wù)到同一線程中,使得這些任務(wù)之間不需要處理線程同步的問題。
構(gòu)造方法:
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
使用方法:
ScheduledExecutorService singleThreadScheduledPool = Executors.newSingleThreadScheduledExecutor();
//延遲1秒后,每隔2秒執(zhí)行一次該任務(wù)
singleThreadScheduledPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
Log.v("zxy", "線程:" + threadName + ",正在執(zhí)行");
}
},1,2,TimeUnit.SECONDS);
singleThreadScheduledPool.execute(Runnable r);