使用对象池Pools

梁丘赞
2023-12-01


使用对象池原因

在应用程序中,我们通常会频繁的使用一些对象,比如:StringBuilder,SpareArray,HashMap等。这些对象只在方法内使用,也是一些小对象。它们临时创建,及时销毁,生命周期非常短暂,可以说朝生夕死。但当使用这些对象的地方很多,频繁的创建和销毁对象,对应的是虚拟机频繁的分配对象内存和回收对象内存,这会成为一件消耗性能的事。

对象池Pools

在Android 中,提供了一个工具类android.support.v4.util.Pools,专门用来做对象缓存。它的源代码很简单:

public final class Pools {

    /**
     * Interface for managing a pool of objects.
     *
     * @param <T> The pooled type.
     */
    public interface Pool<T> {

        /**
         * @return An instance from the pool if such, null otherwise.
         */
        @Nullable
        T acquire();

        /**
         * Release an instance to the pool.
         *
         * @param instance The instance to release.
         * @return Whether the instance was put in the pool.
         *
         * @throws IllegalStateException If the instance is already in the pool.
         */
        boolean release(@NonNull T instance);
    }

    private Pools() {
        /* do nothing - hiding constructor */
    }

    /**
     * Simple (non-synchronized) pool of objects.
     *
     * @param <T> The pooled type.
     */
    public static class SimplePool<T> implements Pool<T> {
        private final Object[] mPool;

        private int mPoolSize;

        /**
         * Creates a new instance.
         *
         * @param maxPoolSize The max pool size.
         *
         * @throws IllegalArgumentException If the max pool size is less than zero.
         */
        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--;
                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;
        }
    }

    /**
     * Synchronized) pool of objects.
     *
     * @param <T> The pooled type.
     */
    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);
            }
        }
    }

Pools类是一个final类,且构造方法为private,所以该类既不能继承也不能创建对象。

Pool接口提供了两个方法acquire和release,acquire方法是从对象池中取出一个对象,release方法是将一个对象放入对象池中。

SimplePool类实现了Pool接口,并提供了acquire和release方法的具体是实现。在创建SimplePool对象时,会初始化一个对象数组new Object[maxPoolSize],maxPoolSize为对象池的大小。acquire方法,从对象池中取出对象数组的最后一个对象,对象数组大小减小一,如果对象池没有对象则返回null。release方法,先检验对象池中是否有该对象,如果有则会抛出异常,否则往对象数组中添加一个对象,对象数组大小加一。

SynchronizedPool继承自SimplePool类,它为对象池的线程安全实现,在acquire和release方法中添加了对象锁。

使用对象池

使用SynchronizedPool来创建线程安全的对象池:

public final class SynchronizedPoolHelper {

    /**
     * 对象池的大小
     */
    final static int POOL_SIZE = 10;

    /**
     * 线程安全的对象池
     */
    private final static Pools.SynchronizedPool<StringBuilder> STRING_BUILDER_SYNCHRONIZED_POOL = new Pools.SynchronizedPool<>(POOL_SIZE);

    /**
     * 从对象池中获得一个StringBuilder对象
     *
     * @return 如果对象池中有StringBuilder对象,就返回一个,否则创建一个新对象返回。
     */
    public static StringBuilder obtainStringBuilder() {
        StringBuilder instance = STRING_BUILDER_SYNCHRONIZED_POOL.acquire();
        if (instance != null) {
            return instance;
        }
        return new StringBuilder();
    }

    /**
     * 将StringBuilder对象放回对象池中
     *
     * @param element
     */
    public static boolean releaseStringBuilder(StringBuilder element) {
        element.setLength(0);
        return STRING_BUILDER_SYNCHRONIZED_POOL.release(element);
    }
}

对象池的大小POOL_SIZE,可以根据项目使用对象频繁次数来定。上面类中,主要实现了StringBuilder的对象池,obtainStringBuilder和releaseStringBuilder方法应该是成对出现的,也就是acquire和release方法应该是成对出现的,才能保证对象池一直维持在固定大小。

使用例子:

        StringBuilder stringBuilder = SynchronizedPoolHelper.obtainStringBuilder();//从对象池中获取对象
        stringBuilder.append("string1");
        stringBuilder.append("string2");
        stringBuilder.append("string3");
        String result = stringBuilder.toString();
        SynchronizedPoolHelper.releaseStringBuilder(stringBuilder);//放回对象池
 类似资料: