SimplePool与SynchronizedPool

Android中提供的对象池

在android.support.v4.util包下的Pools类中,分别声明了Pool接口,SimplePool实现类与SynchronizedPool实现类,其中具体的UML关系如下图所示:

image

在上图中,Pool的具体实现类为SimplePool,而SynchronizedPool为SimplePool的子类。

简单对象池(SimplePool)

在讨论了具体的UML关系后,现在我们来看看SimplePool的代码实现,具体代码如下图所示:

  public static class SimplePool<T> implements Pool<T> {
        private final Object[] mPool;//存储对象的数组
        private int mPoolSize;//当前对象池中的对象个数

        public SimplePool(int maxPoolSize) {
            if (maxPoolSize <= 0) {
                throw new IllegalArgumentException("The max pool size must be > 0");
            }
            mPool = new Object[maxPoolSize];//初始化对象池的最大容量
        }
        //从对象池中获取数据
        @Override
        @SuppressWarnings("unchecked")
        public T acquire() {
            if (mPoolSize > 0) {
                final int lastPooledIndex = mPoolSize - 1;
                T instance = (T) mPool[lastPooledIndex];
                mPool[lastPooledIndex] = null;
                mPoolSize--;//当前对象池中对象个数减1
                return instance;
            }
            return null;
        }

        //回收当前对象到对象池中,
        @Override
        public boolean release(@NonNull T instance) {
            if (isInPool(instance)) {//如果对象池中已经有当前对象了,会抛出异常
                throw new IllegalStateException("Already in the pool!");
            }
            if (mPoolSize < mPool.length) {
                mPool[mPoolSize] = instance;
                mPoolSize++;
                return true;
            }
            return false;
        }

        //判断当前对象是否在对象池中
        private boolean isInPool(@NonNull T instance) {
            for (int i = 0; i < mPoolSize; i++) {
                if (mPool[i] == instance) {
                    return true;
                }
            }
            return false;
        }
    }

对于SimplePool的代码其实很好理解,其对象池是以数组的方式来实现的。其中对象池的最大容量是通过用户手动设定。从对象池中获取数据是通过acquire方法。回收当前对象到对象池中是通过release方法。关于这两个方法的详细流程会在下文具体介绍。

关于acquire方法

在acquire方法中,会从对象池中取出对象。具体列子如下图所示:

image

在上图中,当前对象池中存储了10个object对象,当前sPoolSize = 10。当调用acquire()方法时,会获取最后一个对象(也就是 mPool[9],将该对象取出后,会将该位置置为null(mPool9] =null),当前sPoolSize = 9。当再次调用acquire()方法时,会获取mPool[8]位置下的对象。同理将该位置置为null,当前sPoolSize = 8。

总结:acquire()方法总会取当前对象池中存储的最后一个数据。如果有则返回。同时将该位置置为null。反之返回为null。

关于release方法

在release方法中,会将对象缓存到对象池中。如果当前对象已经存在,会抛出异常。反之则存储。具体列子如下图所示:

image

在上图中。当前对象池存储了8个object对象。当前sPoolSize = 8。当调用realse方法将object9对象回收到对象池中去时,会存储在 mPool[8]位置下。且当前sPoolSize = 9,那么当再次调用realse方法将object10对象放入时,会将object10对象存储在mPool[9]位置下。

总结:release( T instance)方法,总会将需要回收的对象存入当前对象池中存储的最后一个数据的下一个位置。如果当前回收的对象已经存在会抛出异常。反之则成功。

同步对象池(SynchronizedPool)

在前面的文章中我们介绍了SimplePool的存取数据的主要实现。细心的小伙伴肯定都已经发现了。在多线程的情况下,如果使用SimplePool肯定是会出现问题的。但是Google已经为我们考虑到了,为我们提供了线程安全的对象池SynchronizedPool,下面我们就来看看SynchronizedPool的具体实现。具体代码如下

  public static class SynchronizedPool<T> extends SimplePool<T> {
        private final Object mLock = new Object();

        /**
         * Creates a new instance.
         *
         * @param maxPoolSize The max pool size.
         *
         * @throws IllegalArgumentException If the max pool size is less than zero.
         */
        public SynchronizedPool(int maxPoolSize) {
            super(maxPoolSize);
        }

        @Override
        public T acquire() {
            synchronized (mLock) {
                return super.acquire();
            }
        }

        @Override
        public boolean release(@NonNull T element) {
            synchronized (mLock) {
                return super.release(element);
            }
        }
    }

SynchronizedPool的代码理解起来也同样非常简单,直接继承SimplePool。并重写了SimplePool的两个方法。并为其加上了锁,保证了多线程情况下使用的安全性。

对象池的使用

上面我们讨论了两种不同的对象池的实现,下面我们来看看对于这两种对象池的使用。这里就使用官方的SynchronizedPool的使用例子(这里对SimplePool的使用也是通用的,根据是否需要多线程操作来选择不同的对象池)。

  public class MyPooledClass {

      //声明对象池的大小
      private static final SynchronizedPool<MyPooledClass> sPool =
              new SynchronizedPool<MyPooledClass>(10);

      //从对象池中获取数据,如果为null,则创建
      public static MyPooledClass obtain() {
         MyPooledClass instance = sPool.acquire();
        return (instance != null) ? instance : new MyPooledClass();
       }

      //回收对象到对象池中。当然你也可以清除对象的状态
      public void recycle() {
           // 清除对象的状态,如果你自己需要的话,
          sPool.release(this);
      }
 }

总结

  • 对于频繁创建的对象,可以考虑使用对象池。
  • 实现对象池的方式有几种,可以采用数组的形式,也可以采用链表的形式。
  • 在实现对象池缓存对象时,需要考虑到线程安全的问题。该加锁就加锁。

转载参考链接://www.greatytc.com/p/40659db0aafd

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,682评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,277评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,083评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,763评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,785评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,624评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,358评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,261评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,722评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,900评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,030评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,737评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,360评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,941评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,057评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,237评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,976评论 2 355