深入理解 Android:线程、同步、消息
Linux 中的 epoll 机制:
epoll 是 Linux 中高效的 IO 复用机制,显著提高大量并发连接下只有少数活跃时 CPU 的利用率;
epoll 无需要遍历整个被监听的文件描述符集合,只需遍历被内核 IO 事件异步唤醒而加入 Ready 队列的文件描述符集合;
epoll 不仅提供
select/poll那种 IO 等待的水平触发(Level Triggered),还提供边缘触发(Edge Triggered),使用户程序能缓存 IO 状态,减少epoll_wait/epoll_pwait调用,提高效率;epoll 用于保存事件的数据结构采用了红黑树,查找效率高;而
select/poll采用数组保存,不仅一次能等待的句柄个数有限,而且查找速度慢;
线程(Thread.cpp):
创建前判断
mCanCallJava变量,如果为true, 则先attach()到 JNI 环境,以便可以调用 JNI 函数;线程函数退出后,会从 JNI 环境
detach(),释放资源; 如果有未detach()的线程,直接abort();无论
mCanCallJava值为true或false,都会调用_threadLoop()函数,它运行在一个循环中,其返回值决定是否退出线程;
同步类(Thread.h):
Mutex:
构造函数传入
type,当type==SHARED表明支持跨进程的线程同步;调用
lock()或tryLock()尝试加锁,根据返回值判断是否成功;系统保证每次只有一个线程加锁成功;操作完后,调用
unlock()释放锁;
AutoLock:
构造函数传入
Mutex对象;在析构函数中自动调用
unlock(),防止忘记调用造成死锁;
Condition:
构造函数传入
type,当type==SHARED表明支持跨进程的条件同步;wait(&mutex)等待;waitRelative(&mutex,time),在time时间内等待,超时退出等待;signal()通知当前等待的线程;broadcast()通知所有等待的线程;Condition对象的方法必须放在Mutex对象的lock()和unlock()之间的范围调用;
原子操作(Atomic.c):
原子操作即最小执行单位,在执行前不会被其他操作打断;
主要函数:
android_atomic_write(): 原子写操作;android_atomic_inc(): 原子自增操作;android_atomic_dec(): 原子自减操作;android_atomic_add(): 原子加法操作;android_atomic_and(): 原子与操作;android_atomic_or(): 原子或操作;android_atomic_cmpxchg(): 原子条件交换操作;
Looper:
功能:封装消息队列,循环读取和分发消息;
主要方法:
Looper(): 创建MessageQueue,关联当前线程;prepare(): 判断关联的Thread是否存在Looper对象(主线程默认会自动创建),不存在则new一个Looper;loop():while(true)循环,调用queue.next()读取message,调用message的target(即Handler) 的dispatchMessage()方法分发消息;
Handler:
发送消息,实际上就是填充消息到关联的
Looper的消息队列;将
Message的target设置为自己,因为消息的处理工作也在Handler中;
HandlerThread:
通过 synchronized 解决了 Looper 可能为空的情况;
MessageQueue:
Android 2.3 以后,核心部分已放到 Native 层的
NativeMessageQueue;它先处理 Native 的Message,再处理 Native 的Request,最后处理 Java 层的Message;enqueueMessage()方法调用了 Native 层Looper的wake(),向管道写入"W"以触发结束等待;next()方法调用了 Native 层Looper的pollOnce(timeoutMillis, outFd, outEvents, outData):参数
timeoutMillis为超时等待时间,-1无需等待,0立即返回;参数
outFd存储发生事件的文件描述符;参数
outEvents存储该文件描述符上发生的事件(可读、可写、错误、中断),这些事件是从 epoll 事件转化来的;参数
outData存储上下文数据,该数据由用户在添加监听时传递;当
epoll_wait()检测到某些文件句柄有事件而返回,如果是管道读端发生事件,则认为是控制命令,直接读取数据;如果是其他 Fd 发生事件,则根据 Request 构造 Response,并 push 到 Response 数组;首先调用 Native 的
Handler处理 Native 的Message,然后处理 Response 数组中带有 callback 的事件;调用 Native 层
Looper.addFd()可添加监控请求,实际调用epoll_ctl增加文件描述符;
参考: