handler原理与生产者消费者模型进行比对

829 阅读3分钟
原文链接: www.ctolib.com

本文主要说明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作为成员变量
图片描述

主线的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方法的调用流程和使用场景

安卓主线程向子线程的分发非常巧妙,不是简单的生产与消费,也是线程间通信的好案例,如果将来有这方面需求完全可以设计一个简单版主线程与子线交互的设计;

查看原文: handler原理与生产者消费者模型进行比对