在日常的开发工作中,我们可能使用或者听说过对象池,线程池以及连接池。本文将介绍对象池的产生缘由,具体实现细节,以及需要注意的问题。
Android中使用对象池的应用有很多,比如下面的这些都是应用了该模式
以一个简单的获取SytledAttributions代码为例,展示一下对象池的应用
// Text colors/sizes come from the text appearance first
final TypedArray ta = context.obtainStyledAttributes(mTabTextAppearance,
android.support.v7.appcompat.R.styleable.TextAppearance);
try {
mTabTextSize = ta.getDimensionPixelSize(
android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize, 0);
mTabTextColors = ta.getColorStateList(
android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor);
} finally {
ta.recycle();
}
想必这段代码都可能写过,那就是在一开始的时候,我们都会被告诫:使用TypedArray结束的时候,一定要调用它的recycle方法。
回想起来,当时自己还很疑惑为什么要这么规定,其实很简单,它使用了对象池。
调用者通过obtain方法从对象池中获取对象,然后使用完毕后,需要使用recycle方法返还给对象池。
上面的介绍中,也或多或少提到了下面的三种角色
在多线程的环境下,我们也会使用对象池。因此做好必要的同步是必须的。
要进行同步处理的通常是这两个方法
下面是一段进行同步处理了的对象池的源码。
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(T element) {
synchronized (mLock) {
return super.release(element);
}
}
}
上述代码为Android中android.support.v4.util提供的Pools中的SynchronizedPool的实现,它使用了synchronized关键字实现同步问题。
为了统一管理对象,建议将对象池设为单例。
应用单例模式的时候,需要确保在多线程并发的情况下保持唯一的实例创建,具体实现方案,可以参考 单例这种设计模式
所谓的脏对象就是指的是当对象被放回对象池后,还保留着刚刚被客户端调用时生成的数据。
脏对象可能带来两个问题
处于对象池中的对象生命周期要比普通的对象要长久。维持大量的对象也是比较占用内存空间的。
以ThreadPoolExecutor为例,它提供了allowCoreThreadTimeOut和setKeepAliveTime两种方法,可以在超时后销毁核心线程。我们在具体的实践中可以参考这个策略。
相对来说,使用对象池client调用也会复杂一些,比如请求对象时有可能出现的阻塞,异常或者null值。这些都需要我们做一些额外的处理,来确保程序的正常运行。
除此之外,还有上面的提到的两个问题,他们分别是
所以当我们想要使用对象池时,需要谨慎的衡量并准确的实现,享受它带来的好处,并避免其带来的问题。