Android Handler 机制(三):Handler 机制与管道 Pipe 机制

本文目录:
一、管道概述
二、Handler为何使用管道?
三、Handler为何采用管道而非Binder?
四、Android 6.0及以后的机制

在深入系统的学习Handler的时候,我们接触到了Looper之所以死循环不会导致CPU使用率过高,是因为使用了Linux下的pipe和epoll机制。

Android的应用层通过Message.java实现队列,利用管道和epoll机制实现线程状态的管理,配合起来实现了Android主线程的消息队列模型。

一、管道概述

管道,其本质是也是文件,但又和普通的文件会有所不同:管道缓冲区大小一般为1页,即4K字节。管道分为读端和写端,读端负责从管道拿数据,当数据为空时则阻塞;写端向管道写数据,当管道缓存区满时则阻塞。

在Handler机制中,Looper.loop方法会不断循环处理Message,其中消息的获取是通过 Message msg = queue.next(); 方法获取下一条消息。该方法中会调用nativePollOnce()方法,这便是一个native方法,再通过JNI调用进入Native层,在Native层的代码中便采用了管道机制。

二、Handler为何使用管道?

我们可能会好奇,既然是同一个进程间的线程通信,为何需要管道呢?

我们知道线程之间内存共享,通过Handler通信,消息池的内容并不需要从一个线程拷贝到另一个线程,因为两线程可使用的内存时同一个区域,都有权直接访问,当然也存在线程私有区域ThreadLocal(这里不涉及)。即然不需要拷贝内存,那管道是何作用呢?

Handler机制中管道作用就是当一个线程A准备好Message,并放入消息池,这时需要通知另一个线程B去处理这个消息。线程A向管道的写端写入数据1(对于老的Android版本是写入字符W),管道有数据便会唤醒线程B去处理消息。管道主要工作是用于通知另一个线程的,这便是最核心的作用。
这里我们通过两张图来展示Handler在Java层和在Native层的逻辑:
Java层:
在这里插入图片描述

Native层:
在这里插入图片描述

三、Handler为何采用管道而非Binder?

handler不采用Binder,并非binder完成不了这个功能,而是太浪费CPU和内存资源了。因为Binder采用C/S架构,一般用于不同进程间的通信。

  • 从内存角度:通信过程中Binder还涉及一次内存拷贝,handler机制中的Message根本不需要拷贝,本身就是在同一个内存。Handler需要的仅仅是告诉另一个线程数据有了。
  • 从CPU角度,为了Binder通信底层驱动还需要为何一个binder线程池,每次通信涉及binder线程的创建和内存分配等比较浪费CPU资源。
    从上面的角度分析可得,Binder用于进程间通信,而Handler消息机制用于同进程的线程间通信,Handler不宜采用Binder。

四、Android 6.0及以后的机制

在Android 6.0及以前的版本使用管道与epoll来完成Looper的休眠与唤醒的。

在Android 6.0及以后的新版本中使用的是eventfd与epoll来完成Looper的休眠与唤醒的。

感兴趣的可以进一步的学习和了解管道的知识及eventfd的知识,并比较一下两种机制的优劣,进而明白Android官方为何对此机制进行调整。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值