Java高併發程式設計:HandlerThread
1. HandlerThread的使用
繼承自Thread,在run()方法中,執行了Looper.prepare()和Looper.loop(),和handler結合使用,實現後臺輪詢執行緒功能
- start()
- quit()
- getLooper()
public class HandlerThreadActivity extends AppCompatActivity {
private TextView mTvServiceInfo;
private HandlerThread mCheckMsgThread;
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_thread_handler);
initBackThread();//建立後臺執行緒
mTvServiceInfo = (TextView) 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();
mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
checkForUpdate();
if (isUpdateInfo) {
mCheckMsgHandler.sendEmptyMessageDelayed(
MSG_UPDATE_INFO, 1000);
}
}
};
}
//模擬從伺服器解析資料
private void checkForUpdate() {
Thread.sleep(1000);//模擬耗時
mHandler.post(new Runnable() {
@Override
public void run() {
String result = "msg";
mTvServiceInfo.setText(result);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
mCheckMsgThread.quit();//釋放資源
}
}
2. HandlerThread原始碼
Handler的構造,其實就是在Handler中持有一個指向該Looper.mQueue物件,當handler呼叫sendMessage方法時,其實就是往該mQueue中去插入一個message,然後Looper.loop()就會取出執行
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
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;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
public int getThreadId() {
return mTid;
}
}
我們要在子執行緒中呼叫Looper.prepare() 為一個執行緒開啟一個訊息迴圈,預設情況下Android中新誕生的執行緒是沒有開啟訊息迴圈的。(主執行緒除外,主執行緒系統會自動為其建立Looper物件,開啟訊息迴圈。) Looper物件通過MessageQueue來存放訊息和事件。一個執行緒只能有一個Looper,對應一個MessageQueue。 然後通過Looper.loop() 讓Looper開始工作,從訊息佇列裡取訊息,處理訊息。
注意:寫在Looper.loop()之後的程式碼不會被執行,這個函式內部應該是一個迴圈,當呼叫mHandler.getLooper().quit()後,loop才會中止,其後的程式碼才能得以執行。
3. HandlerThread的特點
HandlerThread將loop轉到子執行緒中處理,說白了就是將分擔MainLooper的工作量,降低了主執行緒的壓力,使主介面更流暢。
開啟一個執行緒起到多個執行緒的作用。處理任務是序列執行,按訊息傳送順序進行處理。HandlerThread本質是一個執行緒,線上程內部,程式碼是序列處理的。
但是由於每一個任務都將以佇列的方式逐個被執行到,一旦佇列中有某個任務執行時間過長,那麼就會導致後續的任務都會被延遲處理。
HandlerThread擁有自己的訊息佇列,它不會干擾或阻塞UI執行緒。
對於網路IO操作,HandlerThread並不適合,因為它只有一個執行緒,還得排隊一個一個等著。