这个基本的Java对象池是否有效?

时间:2009-07-16 12:10:36

标签: java concurrency object-pooling

以下基本对象池是否有效?我有一个更复杂的基于相同的想法(即保持信号量和BlockingQueue)。我的问题是 - 我需要Semaphore和BlockingQueue吗?我是对的,我不需要做任何同步吗?

import java.util.Collection;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Semaphore;

public final class Pool<T> {

    private final BlockingQueue<T> objects;
    private final Semaphore permits;

    public Pool(Collection<? extends T> objects) {
        // we have as many permits as objects in our pool:
        this.permits = new Semaphore(objects.size());
        this.objects = new ArrayBlockingQueue<T>(objects.size(), false, objects);
    }

    public T borrow() {
        this.permits.acquireUninterruptibly();
        // we have a permit, so there must be one in there:
        return this.objects.poll();
    }

    public void giveBack(T object) {
        this.objects.add(object);
        this.permits.release();
    }
}

7 个答案:

答案 0 :(得分:15)

正如已经指出的那样,单独一个有界的BlockingQueue就足够了。例如,以下代码将执行您想要的操作:

import java.util.Collection;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public final class Pool<T> {

    private final BlockingQueue<T> objects;

    public Pool(Collection<? extends T> objects) {
        this.objects = new ArrayBlockingQueue<T>(objects.size(), false, objects);
    }

    public T borrow() throws InterruptedException {
        return this.objects.take();
    }

    public void giveBack(T object) throws InterruptedException {
        this.objects.put(object);
    }
}

另外,您可能需要考虑使用BlockingQueue.poll()支持一个定义版本的borrow()。

如果您没有有界阻塞队列数据结构,那么您可以在任何数据结构之上施加信号量以创建线程安全绑定行为。

答案 1 :(得分:5)

一个有点修改过的sjlee的例子;允许按需创建昂贵的对象。我的情况不需要任何阻塞工具,因此我用非阻塞队列类型替换它。作为一个好处,没有必要处理InterruptedExceptions。

import java.util.Collection;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

public abstract class ObjectPool<T> {

    private final Queue<T> objects;

    public ObjectPool() {
        this.objects = new ConcurrentLinkedQueue<T>();
    }

    public ObjectPool(Collection<? extends T> objects) {
        this.objects = new ConcurrentLinkedQueue<T>(objects);
    }

    public abstract T createExpensiveObject();

    public T borrow() {
        T t;
        if ((t = objects.poll()) == null) {
            t = createExpensiveObject();
        }
        return t;
    }

    public void giveBack(T object) {
        this.objects.offer(object);   // no point to wait for free space, just return
    }
}

答案 2 :(得分:3)

也许使用堆栈而不是队列?这样就有可能获得仍然位于处理器缓存中的对象。

答案 3 :(得分:2)

使用take()而不是poll(),并使用put()而不是add()。信号量完全是多余的,所以你可以摆脱它。但是,这看起来不错。

答案 4 :(得分:1)

当你从中获取一个条目时,ArrayBlockingQueue创建一个对象并不值得。所以你的池实际上不会保存对象。只有在您的对象创建成本昂贵时,它才有用。

答案 5 :(得分:0)

也许你应该检查对象是否存在,这是我唯一拥有的东西。

编辑:我没有仔细阅读代码。所以我稍微编了一下帖子。 :(

答案 6 :(得分:0)

这是后者的一个更简单和完整的池。 它比最简单的更好,而且很简单。

来自here

/**
 * 
 * @see <a href=http://www.javacodegeeks.com/2013/08/simple-and-lightweight-pool-implementation.html>simple pool</>
 */
abstract static 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());
        }
    }
}