前言
-
线程间如何通讯?
handler通信实现的方案实际上是内存共享的方案
-
为什么线程间不会干扰?
内存管理设计思路优秀
-
为什么wait/notify用武之地不大?
因为handler已经将需要这部分功能进行了linux层的封装
handler学习点:
源码epoll,设计思路,设计模式,异步消息和同步消息,消息屏障/handlerThread IntentServer
activity的启动:
lancher桌面程序,点击屏幕上的app图标,zygot fork一个进程给每一个应用,给每一个应用分配一个jvm,启动虚拟机。java的main函数就在ActivityThread.main()
给每一个应用都分配一个虚拟机的好处?独立空间、隔离、独立的生命周期
流程分析:
1、Looper的创建
ActivityThread.main(String[] args)
//初始化环境
--> Environment.initForCurrentUser();
//启动主线程
--> Looper.prepareMainLooper();
--> prepare(false);@Looper
//如果从ThreadLocal获取到了looper,那就不允许修改了。
--> if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//不存在则new了一个Looper,并保存在ThreadLocal中。
sThreadLocal.set(new Looper(quitAllowed));
//在Looper的私有构造中,MessageQueue进行了初始化。并赋值当前thread给mThread变量
--> mQueue = new MessageQueue(quitAllowed);
--> mThread = Thread.currentThread();
//looper只能被创建一次。
--> if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
--> return sThreadLocal.get();
//
--> Looper.loop();
//获取当前线程中的looper
--> final Looper me = myLooper();
--> return sThreadLocal.get();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//每一个线程都有一个looper,每一个looper都有一个MessageQueue
final MessageQueue queue = me.mQueue;
//for循环,是个死循环。所有的代码都是在handler上运行的
//在for循环中进行分发
--> for (;;) {
//由MessageQueue从队列中取出消息
Message msg = queue.next();
//looper相当于是一个永动机,能够让它停止运行的唯一方式就是msg=null。
//那什么时候回发送一个为null的message呢?1应用退出,2调用quit()
if (msg == null) {
return;
}
//target=handler.
msg.target.dispatchMessage(msg);
//处理消息
--> handleMessage(msg);@Handler
}
2、handler发送消息
通过MessageQueue.enqueueMessage()将消息添加到队列中
Handler.post(@NonNull Runnable r)
--> sendMessageDelayed(getPostMessage(r), 0);
--> sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
Handler.sendMessage(@NonNull Runnable r)
--> sendMessageDelayed(getPostMessage(r), 0);
--> sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
Handler.sendEmptyMessage(int what)
--> sendEmptyMessageDelayed(what, 0);
--> sendMessageDelayed(msg, delayMillis);
--> sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
最终调用的都是 sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
Handler.sendMessageAtTime(@NonNull Message msg, long uptimeMillis)
--> MessageQueue queue = mQueue;
--> enqueueMessage(queue, msg, uptimeMillis);@Handler
// msg.target = this = Handler
--> msg.target = this;
//将消息放到消息队列
--> queue.enqueueMessage(msg, uptimeMillis);@MessageQueue
//队列的插入节点。这个涉及到数据结构与算法。需要去学习下。。。
--> if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p;
prev.next = msg;
}
//如果之前是处于阻塞状态下,需要唤醒looper
if (needWake) {
nativeWake(mPtr);
}
3、Looper从队列中取消息
通过MessageQueue.next()将消息从队列中取出
//next(),取消息。返回的是message对象
handler.next():Message@MessageQueue
//mPtr两个地方被赋值:MessageQueue构造中给一个默认值。然后在调用Looper.quit()后,mQuitting的值会置为true时,mPtr会置为0.
--> final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1;
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//进行休眠nextPollTimeoutMillis。如果为0,则无需等待立即返回。
//如果nextPollTimeoutMillis为-1,则表示无限等待,直到有事件发生为止。在MessageQueue.
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//同步屏障。这个先不管,下面会讲到。
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
//重点是这个
if (msg != null) {
if (now < msg.when) {
//取第一个消息,如果还没到它的执行时间,那就计算剩余时间。
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// 当没有消息处理的时候,nextPollTimeoutMillis置为-1
nextPollTimeoutMillis = -1;
}
//mQuitting一般都为false。在调用Looper.quit()后,mQuitting的值会置为true。那就会跳出循环
if (mQuitting) {
dispose();
//mPtr置为0,将不再进入这个循环
--> mPtr = 0;
return null;
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
}
}
4、ThreadLocal保证Looper唯一性(一个线程只能创建一个looper)
4.1 往ThreadLocal中添加元素
ThreadLocal.set(T value)
--> Thread t = Thread.currentThread();
//先去获取当前threa的中threadLocals对象,threadLocals是个map集合
ThreadLocalMap map = getMap(t);
//Thread.threadLocals,每个thread中都保存着一个ThreadLocalMap
--> return t.threadLocals;
if (map != null)
//如果当前thread中的threadLocals不为空,直接设置值。
map.set(this, value);
else
//如果当前thread中的threadLocals为空,则new一个,再保存
createMap(t, value);
--> t.threadLocals = new ThreadLocalMap(this, firstValue);
//ThreadLocalMap中维护着一个map集合table。也就是Entry对象,key=Thread,value=需要保存的值
--> table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
4.2 从ThreadLocal中取出元素
ThreadLocal.get()
--> Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
//ThreadLocalMap是ThreadLocal中的内部类。
ThreadLocal.ThreadLocalMap
//Entry的key是
--> static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
其他注意点:
1、子线程中维护的Looper,消息队列无消息的时候,调用Looper.quit(),停止looper的轮巡。
--> mQueue.quit(false);
--> synchronized (this) {
if (mQuitting) {
return;
}
//mQuitting置为true,
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
2、阻塞/唤醒机制
nativePollOnce(ptr, nextPollTimeoutMillis)/nativeWake(mPtr)
相关面试题:
1、一个线程有几个 Handler?
可以随便new
2、一个线程有几个 Looper?如何保证?
一个,私有化了构造方法,需要调用Looper.prepare()创建。先从ThreadLocal中取,如果没有才去new
3、Handler 内存泄漏原因?为什么其他的内部类没有说过有这个问题?怎么解决?
本质原因就是,内部类持有了外部类的对象,且两者生命周期不一致。当外部类需要销毁的时候,由于内部类持有外部类的对象导致不能被回收。
Handler发送消息后,enqueueMessage()中Message持有了handler的引用。而handler又持有了activity的引用。
而Handler可以设置延迟发送。如果设置了20min后执行,那Message就一直持有activity的引用20min。如果activity已经关闭,却无法被回收,
造成内存泄漏。
其他内部类没有这个问题是因为它们的生命周期一致。
解决办法:使用static。因为static的对象不会持有外部类的引用,不影响外部类被回收。
4:为何主线程可以new Handler?如果想要在子线程中new Handler 要做些什么准备?
new Handler,在handler的构造中,要获取looper,是从ThreadLocal中获取的,如果获取到的looper为null,说明没有被创建,会导致崩溃。
在ActivityThread.main()中,系统帮我们在主线程创建了looper,所以可以直接在主线程中new Hanaler
而如果在子线程中使用handler,需要我们手动去创建looper。调用Looper.prepare()。并开启消息的接收Looper.loop()。
5:既然可以存在多个 Handler 往 MessageQueue 中添加数据(发消息时各个 Hanaler 可能处于不同线程),那它内部是如何确保线程安全的?
6:我们使用 Message 时应该如何创建它?
Message.obtain(),内部维护了message池,防止无序创建导致oom
7:Looper死循环为什么不会导致应用卡死
应用卡死,实际是amr,操作无响应。是说执行某个消息时间过长,而其他需要执行的消息等待了时间过长,没有被执行,才会执行anr。
同步屏障:
如果队列中有很多消息,那系统是如何保证每16s强制刷新一次屏幕呢?
这就要引入 同步屏障 机制。
定义:
什么是异步消息?需要立刻执行的消息,通过MessageQueue.postSyncBarrier()发送的消息。
什么是同步消息?其他方式发送的所有消息。
1、还记得在MessageQueue.next()中有这样一段代码吗?
Message prevMsg = null;
Message msg = mMessages;
//当msg.target = null时进入。那msg.target啥时候被赋值,啥时候不被赋值呢?
if (msg != null && msg.target == null) {
//去轮巡消息,找到同步消息。当msg.isAsynchronous()=true的时候退出while循环。
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
2、正常发送的都是同步消息,msg.target = 对应的handler:
Handler.sendMessage(@NonNull Message msg)
--> sendMessageDelayed(msg, 0);
--> sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
--> enqueueMessage(queue, msg, uptimeMillis);
//将handler赋值给message的target。这个时候msg.target是有值的。那什么时候不被赋值呢
--> msg.target = this;
3、添加同步屏障。发送异步消息时,msg.target = null
ViewRootImpl.scheduleTraversals()
--> mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//开启同步屏障(发送一个异步消息)
--> postSyncBarrier(SystemClock.uptimeMillis())
//直接往消息队列中插入一个异步消息
--> synchronized (this) {
final int token = mNextBarrierToken++;
//这里没有给msg.target赋值。
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
//发送刷新屏幕的同步消息
--> mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
--> postCallbackDelayed(callbackType, action, token, 0);
--> postCallbackDelayedInternal(callbackType, action, token, delayMillis);
--> synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
4、取消异步屏障
void unscheduleTraversals() {
--> mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
--> synchronized (this) {
Message prev = null;
Message p = mMessages;
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
prev.next = p.next;
needWake = false;
} else {
//给mMessages重新赋值,相当于移除同步屏障
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;
}
p.recycleUnchecked();
// If the loop is quitting then it is already awake.
// We can assume mPtr != 0 when mQuitting is false.
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
--> mChoreographer.removeCallbacks(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
网友评论