Flyweight Pattern (享元模式)

介绍

享元模式是对象池的一种实现。享元模式用来尽可能减少内存使用量,它适合用于可能存在 大量重复对象的场景,来缓存可共享的对象,达到对象共享、避免创建过多对象的效果,这样一来可以提升性能、避免内存移除等。

定义

使用共享对象可有效地支持大量的细粒度的对象。

使用场景

1、系统中存在大量的相似对象。
2、需要缓冲池的场景。

应用

其实享元模式在平时开发过程中,还是能时不时碰见很多地方应用它,列举两个典型的场景:

一、Android Handler机制中 Message 对象缓存池。
二、EventBus 中事件队列中 PendingPost 对象缓存池

其实上述两种方案中,实现机制类似,就以大家最熟悉的 Handler机制 作为应用实例讲解。

Android 应用是事件驱动的,每个事件都会转化为一个系统消息,即 Message。消息中包含了事件相关的信息以及这个消息的处理人--Handler。 每个进程都有一个默认的消息队列,也就是我们的 MessageQueue,这个消息队列维护了一个待处理的消息列表,消息循环不断地从这个队列中取出消息、处理消息。这样就使得应用动态的运作起来。这么一来 Message 必然会产生很多对象,整个应用都是由事件,也即是 Message 来驱动的,系统需要不断地产生 Message、处理 Message 、销毁 Message,那么我么来看看系统是如何解决这个问题的。(本章不是为了讲解Handler机制,具体的细节可以参看网上的讲解)

首先看一下消息队列 MessageQueue 是如何组织的:

public final class Message implements Parcelable {
  Message next;
  ...
}

public final class MessageQueue {
  Message mMessages;
  ...
}

MessageQueue 是以单链表的形式构成的 Queue。其中 mMessages 相当于 head, 由 Message 中的 next 串联起来组成一个Queue。 上边说够了 MessageQueue 维护了一个待处理的消息列表,即 Message 列表。

知道了这个以后,我们看看系统如何共享对象的。

public final class Message implements Parcelable {
    public static final Object sPoolSync = new Object();
    private static Message sPool;    // 回收的Message对象池
    private static int sPoolSize = 0;

   // 获取一个新的Message对象,优先从全局对象池中获取。这会让我们在大多数情况下避免创建新的对象。
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
}

平时我们创建Message的时候一般都是:Message.obtain()

在 Message 中也维护了一个单链表结构的 Message对象缓存池,缓存池中Message最大个数是50个。 当需要创建一个Message时,会优先从缓存池中获取,当缓存池中没有时,才会进行Message对象的创建。

当消息 Message 被处理了以后会进行回收,我们看一下回收代码:

        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;

        // 把创建的Message对象放入对象池中
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }

上述的代码很清楚了,首先把Message对象的状态都清空,之后放入公共全局对象池中去,后续使用。

以上就是 享元模式 的经典案例。

你可能感兴趣的:(Flyweight Pattern (享元模式))