概述
前面分析了很多并發編程方面的東西,但是都是Java層面的,其實Google原生也提供了一些類方便我們進行并發編程,比較常見的有HandlerThread,IntentService,AsyncTask,除此之外還有一些第三方框架Volley,Picasso等。
研究這些類以及開源框架的實現,可以讓我們更好地理解并發編程,甚至是自己也可以寫一個異步框架也不是什么難事,下面就來從源碼的角度按照順序來先分析一下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()方法必須首先被調用。
看過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;
}
構造方法中新加了一個線程優先級
run方法
@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;
}
getLooper
獲取子線程的Looper
public Looper getLooper() {
//如果線程已經消亡,就返回null
if (!isAlive()) {
return null;
}
//如果線程已經創建了,就在此處停留等待Looper創建完成之后
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
//等待線程被創建
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
quit方法
public boolean quit()
//獲取looper
Looper looper = getLooper();
//退出looper
if (looper != null) {
looper.quit();
return true;
}
return false;
}
quitSafely
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
跟quit方法的唯一區別在于looper.quit()變成了looper.quitSafely(),現在具體分析一下這兩個方法的區別
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
一個傳入了false,一個傳入了true,繼續追蹤
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的消息隊列中的,所以是串行的,所以只適合并發量較少的耗時操作。