Android 线程间通信 - Java 层 - MessagePool

410 阅读3分钟

源码基于 Android S AOSP,源码在线查看地址: cs.android.com/android/pla…

线程间通信在 Android 系统中应用十分广泛,本文是一个系列文章,主要梳理了Android Java层的线程间通信机制-Handler。

上一篇文章梳理了一下Looper、MessageQueue、Handler的源码,以及一些Message中的字段,本篇文章将会梳理一下Message中的MessagePool

还是以一个简单的Handler示例开头

public void egHandler() {
    Looper.prepare();
    Looper.loop();
    
    Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            // TODO; 处理 Event
        }
    };

    new Thread() {
        @Override
        public void run() {
            Message msg = Message.obtain(); // 注意: 此处和上篇文章中的示例不同
            msg.what = 0;
            handler.sendMessage(msg);
        }
    }.start();
}

为了避免重复的创建以及销毁 Message 对象带来的系统开销,Google 团队在Message.java中搞了一个MessagePool,在MessagePool中缓存了定量的Message对象

上面示例中使用的Message.obtain()是从Pool中拿到一个message对象。

MessagePool

源码路径:frameworks/base/core/java/android/os/Message.java

在Message.java中定义了四个成员变量

// MessagePool 同步锁
public static final Object sPoolSync = new Object();
// MessagePool Node节点
private static Message sPool;
// MessagePool Node个数
private static int sPoolSize = 0;
// MessagePool 最大容量
private static final int MAX_POOL_SIZE = 50;

从MessagePool中获取一个message对象,需要调用obtain方法,该方法重载了多个

obtain message

Message.obtain()

public static Message obtain() {
    // 上锁
    synchronized (sPoolSync) {
        if (sPool != null) {
            // 从sPool链表拿出头节点
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

Message.obtain(Message orig)

public static Message obtain(Message orig) {
    // 获取一个message
    Message m = obtain();
    // 将m和形参orig同步
    m.what = orig.what;
    m.arg1 = orig.arg1;
    m.arg2 = orig.arg2;
    m.obj = orig.obj;
    m.replyTo = orig.replyTo;
    m.sendingUid = orig.sendingUid;
    m.workSourceUid = orig.workSourceUid;
    if (orig.data != null) {
        m.data = new Bundle(orig.data);
    }
    m.target = orig.target;
    m.callback = orig.callback;

    return m;
}

Message.obtain(Handler h)

public static Message obtain(Handler h) {
    Message m = obtain();
    // 单独为新msg设置handler
    m.target = h;

    return m;
}

另外还有一些构造方法,整体实现思路差不多。

recycle message

Message.recycle

public void recycle() {
    if (isInUse()) {
        // InUse中被释放会抛出异常
        if (gCheckRecycle) {
            throw new IllegalStateException("This message cannot be recycled because it "
                                            + "is still in use.");
        }
        return;
    }
    // 释放
    recycleUnchecked();
}

Message.recycleUnchecked

@UnsupportedAppUsage
void recycleUnchecked() {
    // Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
    // 初始化flag,标记为InUse
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = UID_NONE;
    workSourceUid = UID_NONE;
    when = 0;
    target = null;
    callback = null;
    data = null;

    // 上锁,将需要释放的msg插入到链表头
    synchronized (sPoolSync) {
        // 注意这里,回收的过程中会判断当前链表的长度是否大于最大长度
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}

recycle与recycleUnchecked的区别在于:

  • recycleUnchecked 不会检查当前msg是否在使用中,而是会直接回收掉该msg,放在链表的头部
  • recycle 会判断当前的msg是否在使用,在使用中会抛出异常,非使用中直接调用recycleUnchecked进行回收

另外,recycleUnchecked不支持app是否,App中只能是否recycle

Message.isInUse

// Message 中两个成员变量
/*package*/ static final int FLAG_IN_USE = 1 << 0;

/** If set message is asynchronous */
/*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;

/*package*/ boolean isInUse() {
    return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}

Message.markInUse

@UnsupportedAppUsage
/*package*/ void markInUse() {
	flags |= FLAG_IN_USE;
}

这个flag的判断方式我有点不理解,还不如直接用数字判断,例如flag = 1就是InUse,难道是为了判断的更快一点采用|、&的方式?

理解为什么这么做的大佬在下面评论一下,不吝指出。