Apache common pool2 对象池

对象池的容器:包含一个指定数量的对象。从池中取出一个对象时,它就不存在池中,直到它被放回。在池中的对象有生命周期:创建,验证,销毁,对象池有助于更好地管理可用资源,防止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();
            }
        }
    }

}
原文地址:https://www.cnblogs.com/jinzhiming/p/5120578.html