文章

池化技术

池化技术

单链表

Pools

Pools 总结

  1. 对象池缓存池,无需多线程同步用 SimplePool,需要多线程同步用 SynchronizedPool
  2. 对象缓存池用的是数组
  3. 从缓存中取对象和释放对象都是取/存数组中的最后一个

Pools 源码

Android 包 androidx.core.util 下有个工具类 Pools,为开发者提供了两种对象池,没有同步控制的 SimplePool 和 有同步控制(访问加锁)的 SynchronizedPool(继承自 SimplePool),方便开发者根据需要创建对应类型的对象池

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// Pools androidx1.3.1
public final class Pools {
    private Pools() {
    }
    // 对象池接口
    public interface Pool<T> {
        // 从池中获取一个对象,没有则返回null
        @Nullable
        
        // 释放对象,将对象放入对象池中,如果对象已经在池中类,会抛出IllegalStateException异常;成功释放(池中有多余的空间)返回true;否则,返回fals
        T acquire();
        boolean release(@NonNull T instance); // @throws IllegalStateException
    }
    /**
     * 没有同步控制的简单对象池
     */
    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;
        }
    }
 
    /**
     * 有同步控制(访问加锁)的对象池
     */
    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 使用

  • Message
  • MotionEvent,
  • TouchTarget 等都是单链表的对象缓存池
  • TabLayout.newTab

private static final Pools.Pool<Tab> tabPool = new Pools.SynchronizedPool<>(16);

VelocityTracker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public final class VelocityTracker {
    private static final SynchronizedPool<VelocityTracker> sPool =
            new SynchronizedPool<VelocityTracker>(2);

    static public VelocityTracker obtain() {
        VelocityTracker instance = sPool.acquire();
        return (instance != null) ? instance : new VelocityTracker(null);
    }
    
    public void recycle() {
        if (mStrategy == null) {
            clear();
            sPool.release(this);
        }
    }
    
}

AsyncLayoutInflater

1
2
3
4
// AsyncLayoutInflater
private static class InflateThread extends Thread {
	private Pools.SynchronizedPool<InflateRequest> mRequestPool = new Pools.SynchronizedPool(10);
}

案例

SynchronizedPool

SynchronizedPool 官方案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 官方例子
public class MyPooledClass {
    private static final SynchronizedPool<MyPooledClass> sPool =
             new SynchronizedPool<MyPooledClass>(10);
 
    public static MyPooledClass obtain() {
        MyPooledClass instance = sPool.acquire();
        return (instance != null) ? instance : new MyPooledClass();
    }
 
    public void recycle() {
       // 必要时,先重置状态
       sPool.release(this);
    }
    // ...
}

SynchronizedPool 示例 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class PoolsDemo {

    private String date;

    private static final Pools.SynchronizedPool<PoolsDemo> sPool =
            new Pools.SynchronizedPool<PoolsDemo>(5);

    private PoolsDemo() {
        date = DateUtils.formatDateToString(System.currentTimeMillis());
    }

    public static PoolsDemo obtain() {
        PoolsDemo instance = sPool.acquire();
        return (instance != null) ? instance : new PoolsDemo();
    }

    private void clear() {
        // 如果需要,清理状态
    }

    public void recycle() {
        // Clear state if needed.
        this.clear();
        sPool.release(this);
    }

    @Override
    public String toString() {
        return "PoolsDemo{" +
                "date='" + date + '\'' +
                '}';
    }
}

ObjectPool

ObjectPool 提供了可回收对象的可能,系统 hide 的 API,在 Activity 生命周期用到了

ObjectPool 源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
 * An object pool that can provide reused objects if available.
 * @hide
 */
class ObjectPool {

    private static final Object sPoolSync = new Object();
    private static final Map<Class, ArrayList<? extends ObjectPoolItem>> sPoolMap =
            new HashMap<>();

    private static final int MAX_POOL_SIZE = 50;

    /**
     * Obtain an instance of a specific class from the pool
     * @param itemClass The class of the object we're looking for.
     * @return An instance or null if there is none.
     */
    public static <T extends ObjectPoolItem> T obtain(Class<T> itemClass) {
        synchronized (sPoolSync) {
            @SuppressWarnings("unchecked")
            final ArrayList<T> itemPool = (ArrayList<T>) sPoolMap.get(itemClass);
            if (itemPool != null && !itemPool.isEmpty()) {
                return itemPool.remove(itemPool.size() - 1);
            }
            return null;
        }
    }

    /**
     * Recycle the object to the pool. The object should be properly cleared before this.
     * @param item The object to recycle.
     * @see ObjectPoolItem#recycle()
     */
    public static <T extends ObjectPoolItem> void recycle(T item) {
        synchronized (sPoolSync) {
            @SuppressWarnings("unchecked")
            ArrayList<T> itemPool = (ArrayList<T>) sPoolMap.get(item.getClass());
            if (itemPool == null) {
                itemPool = new ArrayList<>();
                sPoolMap.put(item.getClass(), itemPool);
            }
            // Check if the item is already in the pool
            final int size = itemPool.size();
            for (int i = 0; i < size; i++) {
                if (itemPool.get(i) == item) {
                    throw new IllegalStateException("Trying to recycle already recycled item");
                }
            }

            if (size < MAX_POOL_SIZE) {
                itemPool.add(item);
            }
        }
    }
}

/**
 * Base interface for all lifecycle items that can be put in object pool.
 *
 * @hide
 */
public interface ObjectPoolItem {
    /**
     * Clear the contents of the item and putting it to a pool. The implementation should call
     * {@link ObjectPool#recycle(ObjectPoolItem)} passing itself.
     */
    void recycle();
}

servertransaction 目录下的基本都用到了

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
public class TestObjectPoolItem implements ObjectPoolItem {
    private String date;
    public TestObjectPoolItem() {
        date = DateUtils.formatDateToString(System.currentTimeMillis());
    }
    @Override
    public void recycle() {
        date = "";
    }
}

item = ObjectPool.obtain(TestObjectPoolItem::class.java)
ObjectPool.recycle(item)
本文由作者按照 CC BY 4.0 进行授权