对象池的容器:包含一个指定数量的对象。从池中取出一个对象时,它就不存在池中,直到它被放回。在池中的对象有生命周期:创建,验证,销毁,对象池有助于更好地管理可用资源,防止JVM内部大量临时小对象,频繁触发垃圾回收,造成系统暂停。有许多的使用示例。特别是在应用服务器数据源池,线程池等都是对象池的使用,下面情况适合使用对象池:
- 同样的对象高频率使用
- 对象太大消耗很多内存
- 对象初始化需要时间
- 对象内涉及IO操作 (Streams, Sockets, DB, etc.)
- 对象并不是线程安全时。
很多人使用 Apache Commons Pool.它有ObjectPool的接口,ObjectPoolFactory,PoolableObjectFactory和许多的实现。有addObject方法,borrowObject,invalidateObject,返回object添加,删除和返回对象。 PoolableObjectFactory定义对象池的操作行为,并提供各种回调。
但是Apache Commons Pool不是一个轻量开销的对象池,它很多方法采用了不建议使用的旧的Java的关键字synchronized。而Java 5中引入了Executor框架Java并发(多线程)。这里是最好的Executor框架。
package easypool; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; public abstract class ObjectPool<T>
{
private ConcurrentLinkedQueue<T> pool; private ScheduledExecutorService executorService; /**
* Creates the pool.
*
* @param minIdle minimum number of objects residing in the pool
*/
public ObjectPool(final int minIdle) {
// initialize pool
initialize(minIdle);
} /**
* Creates the pool.
*
* @param minIdle minimum number of objects residing in the pool
* @param maxIdle maximum number of objects residing in the pool
* @param validationInterval time in seconds for periodical checking of minIdle / maxIdle conditions in a separate thread.
* When the number of objects is less than minIdle, missing instances will be created.
* When the number of objects is greater than maxIdle, too many instances will be removed.
*/
public ObjectPool(final int minIdle, final int maxIdle, final long validationInterval) {
// initialize pool
initialize(minIdle); // check pool conditions in a separate thread
executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(new Runnable()
{
@Override
public void run() {
int size = pool.size();
if (size < minIdle) {
int sizeToBeAdded = minIdle - size;
for (int i = 0; i < sizeToBeAdded; i++) {
pool.add(createObject());
}
} else if (size > maxIdle) {
int sizeToBeRemoved = size - maxIdle;
for (int i = 0; i < sizeToBeRemoved; i++) {
pool.poll();
}
}
}
}, validationInterval, validationInterval, TimeUnit.SECONDS);
} /**
* Gets the next free object from the pool. If the pool doesn't contain any objects,
* a new object will be created and given to the caller of this method back.
*
* @return T borrowed object
*/
public T borrowObject() {
T object;
if ((object = pool.poll()) == null) {
object = createObject();
} return object;
} /**
* Returns object back to the pool.
*
* @param object object to be returned
*/
public void returnObject(T object) {
if (object == null) {
return;
} this.pool.offer(object);
} /**
* Shutdown this pool.
*/
public void shutdown() {
if (executorService != null) {
executorService.shutdown();
}
} /**
* Creates a new object.
*
* @return T new object
*/
protected abstract T createObject(); private void initialize(final int minIdle) {
pool = new ConcurrentLinkedQueue<T>(); for (int i = 0; i < minIdle; i++) {
pool.add(createObject());
}
}
}
package easypool; public class ExportingProcess { private String location; private long processNo = 0; public ExportingProcess(String location, long processNo) {
this.location = location;
this.processNo = processNo; // doing some time expensive calls / tasks
// ... // for-loop is just for simulation
for (int i = 0; i < Integer.MAX_VALUE; i++) {
} System.out.println("Object with process no. " + processNo + " was created");
} public String getLocation() {
return location;
} public long getProcessNo() {
return processNo;
} @Override
public String toString() {
return "ExportingProcess{" + "processNo=" + processNo + '}';
}
}
package easypool; public class ExportingTask implements Runnable { private ObjectPool<ExportingProcess> pool; private int threadNo; public ExportingTask(ObjectPool<ExportingProcess> pool, int threadNo) {
this.pool = pool;
this.threadNo = threadNo;
} public void run() {
// get an object from the pool
ExportingProcess exportingProcess = pool.borrowObject(); System.out.println("Thread " + threadNo +
": Object with process no. " + exportingProcess.getProcessNo() + " was borrowed"); // do something
// ... // for-loop is just for simulation
for (int i = 0; i < 100000; i++) {
} // return ExportingProcess instance back to the pool
pool.returnObject(exportingProcess); System.out.println("Thread " + threadNo +
": Object with process no. " + exportingProcess.getProcessNo() + " was returned");
}
}
package easypool; import org.junit.After;
import org.junit.Before;
import org.junit.Test; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong; public class TestObjectPool
{
private ObjectPool<ExportingProcess> pool; private AtomicLong processNo = new AtomicLong(0); @Before
public void setUp() {
// Create a pool of objects of type ExportingProcess. Parameters:
// 1) Minimum number of special ExportingProcess instances residing in the pool = 4
// 2) Maximum number of special ExportingProcess instances residing in the pool = 10
// 3) Time in seconds for periodical checking of minIdle / maxIdle conditions in a separate thread = 5.
// When the number of ExportingProcess instances is less than minIdle, missing instances will be created.
// When the number of ExportingProcess instances is greater than maxIdle, too many instances will be removed.
// If the validation interval is negative, no periodical checking of minIdle / maxIdle conditions
// in a separate thread take place. These boundaries are ignored then.
pool = new ObjectPool<ExportingProcess>(4, 10, 5)
{
protected ExportingProcess createObject() {
// create a test object which takes some time for creation
return new ExportingProcess("/home/temp/", processNo.incrementAndGet());
}
};
} @After
public void tearDown() {
pool.shutdown();
} @Test
public void testObjectPool() {
ExecutorService executor = Executors.newFixedThreadPool(8); // execute 8 tasks in separate threads
executor.execute(new ExportingTask(pool, 1));
executor.execute(new ExportingTask(pool, 2));
executor.execute(new ExportingTask(pool, 3));
executor.execute(new ExportingTask(pool, 4));
executor.execute(new ExportingTask(pool, 5));
executor.execute(new ExportingTask(pool, 6));
executor.execute(new ExportingTask(pool, 7));
executor.execute(new ExportingTask(pool, 8)); executor.shutdown();
try {
executor.awaitTermination(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试》》》》》》》》》》》》》》》》》》》》》
package test;
public class StringFormat {
public String format(String str)
{
return "formated:"+str;
}
}
package test;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject; public class StringFormatFactory
extends BasePooledObjectFactory<StringFormat> { @Override
public StringFormat create() {
System.out.println("create object");
return new StringFormat();
} /**
* Use the default PooledObject implementation.
*/
@Override
public PooledObject<StringFormat> wrap(StringFormat buffer) {
return new DefaultPooledObject<StringFormat>(buffer);
} /**
* When an object is returned to the pool, clear the buffer.
*/
@Override
public void passivateObject(PooledObject<StringFormat> pooledObject) {
System.out.println("Object been returned to pool");
} // for all other methods, the no-op implementation
// in BasePooledObjectFactory will suffice
}
package test;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List; import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig; public class StringProcessor { private ObjectPool<StringFormat> pool; public StringProcessor(ObjectPool<StringFormat> pool) {
this.pool = pool;
} /**
* Dumps the contents of the {@link Reader} to a String, closing the
* {@link Reader} when done.
*/
public void process(List<String> strList) {
for (String str : strList) {
Thread thread = new StringProcessThread(pool, str);
thread.start();
} //设置等待两秒,等待线程结束
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} public static void main(String[] args) throws IOException { GenericObjectPoolConfig conf = new GenericObjectPoolConfig();
conf.setMaxTotal(3);
conf.setMaxIdle(2);
conf.setMinIdle(2); StringProcessor stringProcessor = new StringProcessor(
new GenericObjectPool<StringFormat>(new StringFormatFactory(),conf));
List<String> strList = new ArrayList<String>();
strList.add("123");
strList.add("456");
strList.add("789");
strList.add("111");
strList.add("222");
strList.add("333");
stringProcessor.process(strList);
}
}
package test;
import org.apache.commons.pool2.ObjectPool; public class StringProcessThread extends Thread {
private ObjectPool<StringFormat> pool;
private String toProcessStr; public StringProcessThread(ObjectPool<StringFormat> pool,
String toProcessStr) {
this.pool = pool;
this.toProcessStr = toProcessStr;
} public void run() {
StringFormat stringFormat = null;
try {
stringFormat = pool.borrowObject();
String formattedStr = stringFormat.format(toProcessStr);
System.out.println(formattedStr);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (stringFormat != null) {
pool.returnObject(stringFormat);
}
} catch (Exception e) {
e.printStackTrace();
}
}
} }