亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

安卓中handler原理與生產(chǎn)者消費(fèi)者模型比較

TNFE / 505人閱讀

摘要:本文主要說(shuō)明內(nèi)部消息機(jī)制用模擬進(jìn)行演示并用圖簡(jiǎn)單說(shuō)明并與生產(chǎn)者與消費(fèi)者模型進(jìn)行比對(duì)代碼地址需要解決的問(wèn)題主線程怎樣跟子線程進(jìn)行通信子線程生產(chǎn)的資源如何傳給主線程子線程如何進(jìn)行等待完成耗時(shí)操作才給主線程傳遞消息為何只能在主線程才能創(chuàng)建子線程想

本文主要說(shuō)明android內(nèi)部消息機(jī)制,用java模擬進(jìn)行演示,并用圖簡(jiǎn)單說(shuō)明.并與生產(chǎn)者與消費(fèi)者模型進(jìn)行比對(duì);

git代碼地址

需要解決的問(wèn)題:
1,主線程怎樣跟子線程進(jìn)行通信,子線程生產(chǎn)的資源,如何傳給主線程?
2,子線程如何進(jìn)行等待,完成耗時(shí)操作才給主線程傳遞消息?
3,為何只能在主線程才能創(chuàng)建handler,子線程想創(chuàng)建該怎么辦?
4,主線程如何與handler/message/looper...進(jìn)行結(jié)合的?
建議帶著問(wèn)題直接看源碼,放到eclipse或者as或者intellj中實(shí)際運(yùn)行后,理解handler運(yùn)行原理;

1 生產(chǎn)者與消費(fèi)者模型:

github地址:生產(chǎn)者與消費(fèi)者
代碼中展示,生產(chǎn)者與消費(fèi)者是分別是兩個(gè)線程,生產(chǎn)或者消耗的資源是num,而Resource3類是個(gè)生產(chǎn)線(queue),
通過(guò)java的BlockingQueue對(duì)生產(chǎn)與消費(fèi)進(jìn)行阻塞,最終通過(guò)main方法創(chuàng)建線程進(jìn)行生產(chǎn)與消費(fèi);

2 handler在android中既是生產(chǎn)者也是消費(fèi)者

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

其中子線程的是真正的生產(chǎn)者,把生產(chǎn)后的結(jié)果給了message.obj,然后handler.sendMessage進(jìn)行入列messagequeue(給了生產(chǎn)線);
 @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("請(qǐng)求錯(cuò)誤")&&(!json.contains("ConnectionRefused"))))
                    alarmList = GsonUtils.jsonToList(json, Alarm.class);
                    Message message = Message.obtain();
                    message.what = 0 ;
                    message.obj = alarmList;
                    handler.sendMessage(message);

            }
之后looper進(jìn)行dispatch之后,再進(jìn)行handlerMessage在handler進(jìn)行消費(fèi);可見(jiàn),android中handler的機(jī)制與生產(chǎn)者消費(fèi)者模型最大區(qū)別是生產(chǎn)者消費(fèi)者分別是兩個(gè)線程,而handler既扮演生產(chǎn)者又是消費(fèi)者卻只是主線程的對(duì)象!
handler是通過(guò)消息傳遞(message)把json解析出來(lái)的東西,傳遞給主線程的messagequeue,然后handler又自己進(jìn)行處理,這當(dāng)中handler必須等待子線程生產(chǎn)完成(耗時(shí)操作完成);
文章開始提出的第二個(gè)問(wèn)題:2,子線程如何進(jìn)行等待,完成耗時(shí)操作才給主線程傳遞消息? 其中原理不是利用java的blockqueue之類.其中messagequeue是個(gè)鏈表,阻塞機(jī)制與底層的C++相關(guān)聯(lián): 深入理解messagequeue這文章沒(méi)有看懂,希望可以拋磚引玉;
另外,handler處理完message之后如何又循環(huán)把message填入隊(duì)尾的機(jī)制也不是很理解;
3,為何只能在主線程才能創(chuàng)建handler....? 4,主線程如何與handler/message/looper...進(jìn)行結(jié)合的?(通過(guò)threadlocal這個(gè)map)

如下圖解釋:handler為何只能在主線程以及如何保生產(chǎn)消費(fèi)是同一個(gè)handler

其中l(wèi)ooper的角色是管理既是管理messagequeue的,又是分發(fā)消息給handler的中間者,

handler類圖如下,可見(jiàn)handler中既有l(wèi)ooper,又有messagequeue作為成員變量

主線的main方法中有l(wèi)ooper.papare(),子線程沒(méi)有,給localThread這個(gè)map進(jìn)行設(shè)置值:
threadlocal這個(gè)map進(jìn)行set,其中key=主線程,val=looper(looper又有messagequeue)
源碼中,主線程:
在程序啟動(dòng)的時(shí)候,系統(tǒng)已經(jīng)幫我們自動(dòng)調(diào)用了Looper.prepare()方法。查看ActivityThread中的main()

public static void main(String[] args) {  
SamplingProfilerIntegration.start();  
CloseGuard.setEnabled(false);  
Environment.initForCurrentUser();  
EventLogger.setReporter(new EventLoggingReporter());  
Process.setArgV0("");  
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");  
}  

請(qǐng)注意Looper.prepareMainLooper():

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

原理基本結(jié)束:其他的運(yùn)用如下,道理也是相通的,
理解AsyncTask的源碼
Android:主線程如何向子線程發(fā)送消息
至于hander.post()的有不錯(cuò)的文章:Handler中post方法的調(diào)用流程和使用場(chǎng)景

Queue的為何必須配合message.what?

message入隊(duì)的時(shí)候可能是按照某種順序直接添加,但是出隊(duì)的時(shí)候可能是按照子線程生產(chǎn)產(chǎn)品時(shí)間最短的先出隊(duì)進(jìn)行處理(或者隊(duì)列重排序(個(gè)人感覺(jué)可能性不大)),這點(diǎn)與生產(chǎn)消費(fèi)的
模型完全不同,如果按照生產(chǎn)一個(gè),消費(fèi)一個(gè),生產(chǎn)時(shí)間長(zhǎng)的排在前面,先來(lái)后到的話,生產(chǎn)時(shí)間短的排在后面就會(huì)一直得不到消費(fèi),用戶體驗(yàn)一定差;
這個(gè)時(shí)候,一定需要一個(gè)電話號(hào)碼(message.what),這時(shí)候handler就相當(dāng)于交換機(jī),通知消費(fèi)者該如何處理,因?yàn)樽泳€程的生產(chǎn)時(shí)間是隨機(jī),誰(shuí)也不知道m(xù)essagequeue排序是如何的,開發(fā)者不能根據(jù)子線程耗時(shí)長(zhǎng)短估計(jì)處理順序,萬(wàn)一遇到處理時(shí)間相同,消費(fèi)邏輯不同又該怎么辦,所以一定要用what區(qū)分。

為何子線程不直接把結(jié)果壓入messagequeue中?

一開始感覺(jué)安卓完全可以做個(gè)標(biāo)志,類似于msg.what的標(biāo)志,作為一個(gè)map的key直接壓入隊(duì)列messagequeue,之后主線程直接取這個(gè)get這個(gè)標(biāo)志就可以了,然后自己寫對(duì)應(yīng)的邏輯就可以了,但這會(huì)造成在子線程主線程直接與messageQueue進(jìn)行交互,既要處理子線程間的競(jìng)爭(zhēng),這時(shí)又要對(duì)主線程進(jìn)行休眠喚醒等操作,對(duì)messageQueue的開啟無(wú)限循環(huán)再get到相應(yīng)的message,還要處理對(duì)子線程的操作,這些復(fù)雜的操作都在與主線程的交互sendMessage的時(shí)候完成;

當(dāng)然文章開始提出的那幾個(gè)問(wèn)題沒(méi)有完全解決,但是通過(guò)這篇文章,能看到安卓中UI線程與子線程交互的巧妙之處;

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/72308.html

相關(guān)文章

  • 金三銀四,2019大廠Android高級(jí)工程師面試題整理

    摘要:原文地址游客前言金三銀四,很多同學(xué)心里大概都準(zhǔn)備著年后找工作或者跳槽。最近有很多同學(xué)都在交流群里求大廠面試題。 最近整理了一波面試題,包括安卓JAVA方面的,目前大廠還是以安卓源碼,算法,以及數(shù)據(jù)結(jié)構(gòu)為主,有一些中小型公司也會(huì)問(wèn)到混合開發(fā)的知識(shí),至于我為什么傾向于混合開發(fā),我的一句話就是走上編程之路,將來(lái)你要學(xué)不僅僅是這些,豐富自己方能與世接軌,做好全棧的裝備。 原文地址:游客kutd...

    tracymac7 評(píng)論0 收藏0
  • 2019 Android 高級(jí)面試題總結(jié)

    摘要:子線程往消息隊(duì)列發(fā)送消息,并且往管道文件寫數(shù)據(jù),主線程即被喚醒,從管道文件讀取數(shù)據(jù),主線程被喚醒只是為了讀取消息,當(dāng)消息讀取完畢,再次睡眠。因此的循環(huán)并不會(huì)對(duì)性能有過(guò)多的消耗。 說(shuō)下你所知道的設(shè)計(jì)模式與使用場(chǎng)景 a.建造者模式: 將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。 使用場(chǎng)景比如最常見(jiàn)的AlertDialog,拿我們開發(fā)過(guò)程中舉例,比如Camera...

    wums 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<