9

以下基本对象池是否有效?我有一个基于相同想法的更复杂的(即同时维护信号量和阻塞队列)。我的问题是 - 我需要 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();
    }
}
4

7 回答 7

16

正如已经指出的那样,单独的有界 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()。

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

于 2009-07-16T19:37:22.220 回答
6

一个稍微修改过的 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
    }
}
于 2009-07-28T13:04:41.167 回答
3

也许使用堆栈而不是队列?这提供了获得仍然位于处理器缓存中的对象的机会。

于 2009-11-02T13:13:11.907 回答
2

当您从中获取条目时,ArrayBlockingQueue 创建一个对象毫无价值。所以你的池实际上不会保存对象。只有当您的对象的创建成本很高时,它才会有所帮助。

于 2009-07-17T05:40:12.630 回答
2

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

于 2009-07-16T12:16:00.750 回答
0

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

这里

/**
 * 
 * @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());
        }
    }
}
于 2015-03-12T02:40:24.160 回答
0

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

编辑:我没有仔细阅读代码。所以我编辑了这篇文章。:(

于 2009-07-16T12:14:34.290 回答