1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.common.util; 18 19 /** 20 * Helper class for creating pools of objects. Creating new objects is an 21 * expensive operation, which can lead to significant performance overhead if 22 * new objects of the same type are allocated and destroyed during run time. 23 * These performance issues can be mitigated by reusing unused objects and 24 * reinitializing them, rather than destroying and removing them from memory. 25 * <p> 26 * The object pool pattern provided by the {@link Pool} interface facilitates 27 * the reuse of objects by keeping unused ('released') objects in memory and 28 * making them available for use. This can provide a significant performance 29 * improvement, as objects are only created once and returned to the Pool when 30 * no longer required, rather than destroyed and reallocated. Object 31 * {@link Pools} keep track of these unused objects. An object pool provides two 32 * basic methods for access: 33 * <ul> 34 * <li><b>{@link Pool#acquire()}:</b> Returns an used object if one is 35 * available.</li> 36 * <li><b> {@link Pool#release(Object)}:</b> Adds the given object to the pool, 37 * ready to be reallocated in acquire().</li> 38 * </ul> 39 * <p> 40 * This class contains the interface defining a {@link Pool}, an implementation 41 * based on a fixed length array ({@link SimplePool}) and a synchronized pool 42 * for use with concurrency ({@link SynchronizedPool}). 43 * <p> 44 * A {@link SimplePool} can be used like this: 45 * 46 * <pre> 47 * public class MyPooledClass { 48 * 49 * private static final SynchronizedPool<MyPooledClass> sPool = 50 * new SynchronizedPool<MyPooledClass>(10); 51 * 52 * public static MyPooledClass obtain() { 53 * MyPooledClass instance = sPool.acquire(); 54 * return (instance != null) ? instance : new MyPooledClass(); 55 * } 56 * 57 * public void recycle() { 58 * // Clear state if needed. 59 * sPool.release(this); 60 * } 61 * 62 * . . . 63 * } 64 * </pre> 65 */ 66 public final class Pools { 67 68 /** 69 * Interface for managing a pool of objects. 70 * 71 * @param T The pooled type. 72 */ 73 public static interface Pool<T> { 74 75 /** 76 * Retrieves an object from the pool. Returns null if the pool is empty 77 * and no object is available. 78 * 79 * @return An instance from the pool if available, null otherwise. 80 */ 81 public T acquire(); 82 83 /** 84 * Releases an instance to the pool. This marks the object as reusable 85 * and makes it available through a call to {@link #acquire()}. An 86 * object should not be modified or accessed once it has been released. 87 * 88 * @param instance The instance to release. 89 * @return True if the instance was put in the pool. 90 * @throws IllegalStateException If the instance is already in the pool. 91 */ 92 public boolean release(T instance); 93 } 94 95 private Pools() { 96 /* do nothing - hiding constructor */ 97 } 98 99 /** 100 * Simple (non-synchronized) pool of objects. This class provides a simple, 101 * fixed sized pool of objects. 102 * 103 * @param T The pooled type. 104 */ 105 public static class SimplePool<T> implements Pool<T> { 106 private final Object[] mPool; 107 108 private int mPoolSize; 109 110 /** 111 * Creates a new instance. The parameter defines the maximum number of 112 * objects that can be held in this pool. 113 * 114 * @param maxPoolSize The max pool size. 115 * @throws IllegalArgumentException If the max pool size is less than 116 * zero. 117 */ 118 public SimplePool(int maxPoolSize) { 119 if (maxPoolSize <= 0) { 120 throw new IllegalArgumentException("The max pool size must be > 0"); 121 } 122 mPool = new Object[maxPoolSize]; 123 } 124 125 /** 126 * Returns an object from the pool or null if the pool is empty. 127 * 128 * @return An object from the pool or null if no object is available. 129 */ 130 @Override 131 @SuppressWarnings("unchecked") 132 public T acquire() { 133 if (mPoolSize > 0) { 134 final int lastPooledIndex = mPoolSize - 1; 135 T instance = (T) mPool[lastPooledIndex]; 136 mPool[lastPooledIndex] = null; 137 mPoolSize--; 138 return instance; 139 } 140 return null; 141 } 142 143 /** 144 * Adds an object to the pool. If the pool is already full (its 145 * allocated size has been exceeded), the object is not added and false 146 * is returned. A linear check is performed to ensure that the object is 147 * not already held in the pool. 148 * 149 * @param instance The element to release. 150 * @return True if the object was added to the pool. 151 * @throws IllegalStateException If the object already exists in the 152 * pool. 153 */ 154 @Override 155 public boolean release(T instance) { 156 if (isInPool(instance)) { 157 throw new IllegalStateException("Already in the pool!"); 158 } 159 if (mPoolSize < mPool.length) { 160 mPool[mPoolSize] = instance; 161 mPoolSize++; 162 return true; 163 } 164 return false; 165 } 166 167 /** 168 * Checks if the object already exists in the pool. 169 * @param instance The element to look for. 170 * @return True if the object exists in the pool. 171 */ 172 private boolean isInPool(T instance) { 173 for (int i = 0; i < mPoolSize; i++) { 174 if (mPool[i] == instance) { 175 return true; 176 } 177 } 178 return false; 179 } 180 } 181 182 /** 183 * Synchronized pool of objects. Based on the implementation of a fixed size 184 * pool in {@link SimplePool}, this class provides synchronized concurrent 185 * access to the pool. 186 * 187 * @param T The pooled type. 188 */ 189 public static class SynchronizedPool<T> extends SimplePool<T> { 190 private final Object mLock = new Object(); 191 192 /** 193 * Creates a new instance. 194 * 195 * @param maxPoolSize The max pool size. 196 * @throws IllegalArgumentException If the max pool size is less than 197 * zero. 198 */ 199 public SynchronizedPool(int maxPoolSize) { 200 super(maxPoolSize); 201 } 202 203 /** 204 * Returns an object from the pool or null if the pool is empty. 205 * <p> 206 * Access to the pool is synchronized. 207 * 208 * @return An object from the pool or null if no object is available. 209 */ 210 @Override 211 public T acquire() { 212 synchronized (mLock) { 213 return super.acquire(); 214 } 215 } 216 217 /** 218 * Adds an object to the pool. If the pool is already full (its 219 * allocated size has been exceeded), the object is not added and false 220 * is returned. A linear check is performed to ensure that the object is 221 * not already held in the pool. 222 * <p> 223 * Access to the pool is synchronized. 224 * 225 * @param element The element to be released 226 * @return True if the object was added to the pool. 227 * @throws IllegalStateException If the object already exists in the 228 * pool. 229 */ 230 @Override 231 public boolean release(T element) { 232 synchronized (mLock) { 233 return super.release(element); 234 } 235 } 236 } 237 } 238