handler原理與生產者消費者模型進行比對

本文主要說明android內部消息機制,用java模擬進行演示,並用圖簡單說明.並與生產者與消費者模型進行比對;

git代碼地址

需要解決的問題:
1,主線程怎樣跟子線程進行通信,子線程生產的資源,如何傳給主線程?
2,子線程如何進行等待,完成耗時操作纔給主線程傳遞消息?
3,爲何只能在主線程才能創建handler,子線程想創建該怎麼辦?
4,主線程如何與handler/message/looper...進行結合的?
建議帶着問題直接看源碼,放到eclipse或者as或者intellj中實際運行後,理解handler運行原理;

1 生產者與消費者模型:

github地址:生產者與消費者
代碼中展示,生產者與消費者是分別是兩個線程,生產或者消耗的資源是num,而Resource3類是個生產線(queue),
通過java的BlockingQueue對生產與消費進行阻塞,最終通過main方法創建線程進行生產與消費;

2 handler在android中既是生產者也是消費者

github代碼
看代碼後理解下圖:

handler既是生產與也是消費者

其中子線程的是真正的生產者,把生產後的結果給了message.obj,然後handler.sendMessage進行入列messagequeue(給了生產線);
 @Override
            public void onResponse(Call call, Response response) throws IOException {
                  final String json =   response.body().string();
                //Log.e("json", "success: "+json.toString() );
                if (null!=json && !"".equals(json)&&(!json.contains("請求錯誤")&&(!json.contains("ConnectionRefused"))))
                    alarmList = GsonUtils.jsonToList(json, Alarm.class);
                    Message message = Message.obtain();
                    message.what = 0 ;
                    message.obj = alarmList;
                    handler.sendMessage(message);

            }
之後looper進行dispatch之後,再進行handlerMessage在handler進行消費;可見,android中handler的機制與生產者消費者模型最大區別是生產者消費者分別是兩個線程,而handler扮演生產者與消費者確只是主線程的對象!handler是通過消息傳遞(message)把json解析出來的東西,傳遞給主線程的messagequeue,然後handler又自己進行處理; 文章開始提出的第二個問題:2,子線程如何進行等待,完成耗時操作纔給主線程傳遞消息? 其中原理不是利用java的blockqueue之類.messagequeue是個鏈表,阻塞機制與底層的C++相關聯: 深入理解messagequeue這文章沒有看懂,希望可以拋磚引玉,講解一下具體原理;
另外,handler處理完message之後如何又循環把message填入隊尾的機制也不是很理解;

3,爲何只能在主線程才能創建handler,子線程想創建該怎麼辦?

4,主線程如何與handler/message/looper...進行結合的?(通過threadlocal這個map)

如下圖解釋:handler爲何只能在主線程以及如何保生產消費是同一個handler
handler爲何只能在主線程以及如何保生產消費是同一個handler
其中looper的角色是管理既是管理messagequeue的,又是分發消息給handler的中間者,

handler類圖如下,可見handler中既有looper,又有messagequeue作爲成員變量
圖片描述

handler是否在主線程,是通過looper是否爲空判斷;

主線的main方法中有looper.papare(),子線程沒有,給localThread這個map進行設置值:
threadlocal<T>這個map進行set,其中key=主線程,val=looper(looper又有messagequeue)
源碼中,主線程:
在程序啓動的時候,系統已經幫我們自動調用了Looper.prepare()方法。查看ActivityThread中的main()

public static void main(String[] args) {  
SamplingProfilerIntegration.start();  
CloseGuard.setEnabled(false);  
Environment.initForCurrentUser();  
EventLogger.setReporter(new EventLoggingReporter());  
Process.setArgV0("<pre-initialized>");  
Looper.prepareMainLooper();  
ActivityThread thread = new ActivityThread();  
thread.attach(false);  
if (sMainThreadHandler == null) {  
    sMainThreadHandler = thread.getHandler();  
}  
AsyncTask.init();  
if (false) {  
    Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));  
}  
Looper.loop();  
throw new RuntimeException("Main thread loop unexpectedly exited");  
}  

請注意Looper.prepareMainLooper():

public static final void prepareMainLooper() {  
prepare();  //這步相當於對threadlocal進行set,key=主線程,val=looper(looper又有messagequeue)
setMainLooper(myLooper());  
if (Process.supportsProcesses()) {  
    myLooper().mQueue.mQuitAllowed = false;  
}  
}  

原理基本結束:其他的運用如下,道理也是相通的,
理解AsyncTask的源碼
Android:主線程如何向子線程發送消息
至於hander.post()的有不錯的文章:Handler中post方法的調用流程和使用場景

安卓主線程子線程的分發非常巧妙,不是簡單的生產與消費,也是線程間通信的好案例,如果將來有這方面需求完全可以設計一個簡單版主線程與子線交互的設計;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章