前面分析了不少併發編程方面的東西,可是都是Java層面的,其實Google原生也提供了一些類方便咱們進行併發編程,比較常見的有HandlerThread,IntentService,AsyncTask,除此以外還有一些第三方框架Volley,Picasso等。java
研究這些類以及開源框架的實現,可讓咱們更好地理解併發編程,甚至是本身也能夠寫一個異步框架也不是什麼難事,下面就來從源碼的角度按照順序來先分析一下HandlerThread。編程
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. 複製代碼
一個好用的類用於建立一個自帶Looper的線程。這個Looper能夠用來建立Handler。注意start()方法必須首先被調用。bash
看過Handler的源碼都應該比較熟悉,Handler的消息是須要Looper來進行輪詢的,也就是每一個Handler建立的時候都須要傳入一個Looper,不過咱們平時建立Handler的時候之因此不須要傳入Looper,是由於主線程默認爲咱們建立了一個looper,固然咱們也能夠傳入本身的Looper.因此爲了不每次在子線程中建立Handler都須要建立Looper,Google爲咱們提供了HandlerThread這個類。併發
int mPriority;//線程優先級
int mTid = -1;//線程ID
Looper mLooper;//建立線程的Looper
複製代碼
繼承關係比較簡單,僅僅繼承自Thread,在內部作了一些封裝。框架
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
複製代碼
這個方法Google都沒有註釋,太簡單了,就是傳入一個線程名稱,而後優先級是默認的優先級0異步
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
複製代碼
構造方法中新加了一個線程優先級ide
@Override
public void run() {
//獲取進程ID
mTid = Process.myTid();
//Loopr準備
Looper.prepare();
//建立Looper
synchronized (this) {
mLooper = Looper.myLooper();
//喚醒全部等待的線程
notifyAll();
}
//設置線程優先級
Process.setThreadPriority(mPriority);
//在Looper循環時作一些準備工做
onLooperPrepared();
//開啓循環
Looper.loop();
mTid = -1;
}
複製代碼
獲取子線程的Looperoop
public Looper getLooper() {
//若是線程已經消亡,就返回null
if (!isAlive()) {
return null;
}
//若是線程已經建立了,就在此處停留等待Looper建立完成以後
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
//等待線程被建立
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
複製代碼
public boolean quit() //獲取looper Looper looper = getLooper();
//退出looper
if (looper != null) {
looper.quit();
return true;
}
return false;
}
複製代碼
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
複製代碼
跟quit方法的惟一區別在於looper.quit()變成了looper.quitSafely(),如今具體分析一下這兩個方法的區別post
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
複製代碼
一個傳入了false,一個傳入了true,繼續追蹤ui
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
//移除消息隊列中延遲的消息
removeAllFutureMessagesLocked();
} else {
//移除消息隊列中全部的消息
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
複製代碼
removeAllFutureMessagesLocked方法
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {
//當消息隊列中中的消息的發送時間大於當前時間
//就移除該消息
removeAllMessagesLocked();
} else {
Message n;
for (;;) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
複製代碼
因此看到這裏,quit跟quidSafely的區別就在因而否移除消息隊列中還未發送也就是延遲的消息。
//建立mHandlerThread
mHandlerThread = new HandlerThread("main");
//獲取HandlerThead中的Looper
Looper looper = mHandlerThread.getLooper();
//建立子線程中的Looper
Handler handler = new Handler(looper);
//執行耗時操做
handler.post(new Runnable() {
@Override
public void run() {
//子線程中執行耗時操做
}
});
//界面銷燬的時候須要銷燬Looper
@Override
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit();
}
複製代碼
若是沒有HandlerThread,咱們須要手動去建立一個線程,如今HandlerThread能夠幫咱們簡化這個操做,可是有一點須要注意的是,因爲咱們的異步操做是存放在Handler的消息隊列中的,因此是串行的,因此只適合併發量較少的耗時操做。