具有有界队列的线程池

时间:2011-10-04 15:40:19

标签: java multithreading

我已经看到了线程池执行器实现和它提供的被拒绝的执行策略。但是,我有一个自定义要求 - 我希望有一个回调机制,在达到队列大小限制时我会收到通知,并说当队列大小减少到最大允许队列大小的80%时。

public interface ISaturatedPoolObserver {
 void onSaturated(); // called when the blocking queue reaches the size limit
 void onUnsaturated(); // called when blocking queues size goes below the threshold.
}

我觉得这可以通过子类化线程池执行器来实现,但是是否已经实现了版本?我很乐意在需要时提供更多细节和我的工作,以提供清晰度。

2 个答案:

答案 0 :(得分:5)

  

我希望有一个回调机制,在达到队列大小限制时我会收到通知......

我不会继承执行程序,但我会继承执行程序使用的BlockingQueue。像下面这样的东西应该工作。如果您删除某个条目并且有人将其重新插入,则checkUnsaturated()周围的代码中存在竞争条件。如果这些条件需要完美,则可能必须在队列上进行同步。此外,我不知道执行程序实现使用什么方法,因此您可能不需要覆盖其中的一些。

public class ObservableBlockingQueue<E> extends LinkedBlockingQueue<E> {
     private ISaturatedPoolObserver observer;
     private int capacity;
     public ObservableBlockingQueue(ISaturatedPoolObserver observer,
         int capacity) {
         super(capacity);
         this.observer = observer;
         this.capacity = capacity;
    }
    @Override
    public boolean offer(E o) {
        boolean offered = super.offer(o);
        if (!offered) {
            observer.onSaturated();
        }
        return offered;
    }
    @Override
    public boolean offer(E o, long timeout, TimeUnit unit) throws InterruptedException {
        boolean offered = super.offer(o, timeout, unit);
        if (!offered) {
            observer.onSaturated();
        }
        return offered;
    }
    @Override
    public E poll() {
        E e = super.poll();
        if (e != null) {
             checkUnsaturated();
        }
        return e;
    }
    @Override
    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        E e = super.poll(timeout, unit);
        if (e != null) {
             checkUnsaturated();
        }
        return e;
    }
    @Override
    public E take() throws InterruptedException {
        E e = super.take();
        checkUnsaturated();
        return e;
    }
    @Override
    public boolean remove(E e) throws InterruptedException {
        boolean removed = super.remove(e);
        if (removed) {
            checkUnsaturated();
        }
        return removed;
    }
    private void checkUnsaturated() {
        if (super.size() * 100 / capacity < UNSATURATED_PERCENTAGE) {
            observer.onUnsaturated();
        }
    }
}

答案 1 :(得分:0)

所以这里是基于上面答案的代码。在线程池的工作队列的持续加载期间需要调用饱和和未饱和的调用,并且我相信实现通过使用非阻塞算法来实现它。

此外,此实现可用于阻塞队列的任何实现(原始队列也可以是有界的或无界的)。

我正在使用guava的ForwardingBlockingQueue来编写我的装饰器。任何建议都将不胜感激。

import java.util.Collection;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import com.google.common.util.concurrent.ForwardingBlockingQueue;

/**
 * @version $Id$
 * @param <E> the type of elements held in this blocking queue.
 */
public class BoundObservableBlockingQueue<E> extends ForwardingBlockingQueue<E> {

    /** observer to receive callbacks. */
    private final ISaturatedQueueObserver queueBoundObserver;

    /** original blocking queue being decorated. */
    private final BlockingQueue<E> queueDelegate;

    /** user specified blocking queue bound capacity. */
    private final int boundCapacity;

    /** user specified blocking queue bound capacity. */
    private final int boundThreshold;

    /** flag to represent the saturated state of the queue. */
    private final AtomicBoolean isSaturated = new AtomicBoolean(false);

/**
     * 
     * @param pQueue {@link BlockingQueue
     * @param pQueueBoundObserver {@link ISaturatedQueueObserver}
     * @param pBoundCapacity saturation capacity for the bound queue.
     */
    public BoundObservableBlockingQueue(final BlockingQueue<E> pQueue,
            final ISaturatedQueueObserver pQueueBoundObserver, final int pBoundCapacity) {
        queueDelegate = pQueue;
        queueBoundObserver = pQueueBoundObserver;
        boundCapacity = pBoundCapacity;
        boundThreshold = (int) 0.8 * pBoundCapacity;
    }

    /** {@inheritDoc} */
    @Override
    public final boolean offer(final E e) {
        boolean isOffered = delegate().offer(e);
        checkSaturated();
        return isOffered;
    }

    /** {@inheritDoc} */
    @Override
    public final boolean offer(final E e, final long timeout, final TimeUnit unit) throws InterruptedException {
        boolean isOffered = delegate().offer(e, timeout, unit);
        checkSaturated();
        return isOffered;
    }

    /** {@inheritDoc} */
    @Override
    public final E remove() {
        E element = delegate().remove();
        checkUnsaturated();
        return element;
    }

    /** {@inheritDoc} */
    @Override
    public final E poll() {
        E element = delegate().poll();
        checkUnsaturated();
        return element;
    }

    /** {@inheritDoc} */
    @Override
    public final E poll(final long timeout, final TimeUnit unit) throws InterruptedException {
        E element = delegate().poll(timeout, unit);
        checkUnsaturated();
        return element;
    }

    /** {@inheritDoc} */
    @Override
    public final E take() throws InterruptedException {
        E element = delegate().take();
        checkUnsaturated();
        return element;
    }

    /** {@inheritDoc} */
    @Override
    public final boolean remove(final Object o) {
        boolean isRemoved = delegate().remove(o);
        checkUnsaturated();
        return isRemoved;
    }

    /** {@inheritDoc} */
    @Override
    protected final BlockingQueue<E> delegate() {
        return queueDelegate;
    }

    // thread pool uses this only during invocation of shutdown; in which cases call to unSaturated isn't needed because
    // the queue is no longer ready to accept any more records.
    /** {@inheritDoc} */
    @Override
    public final int drainTo(final Collection<? super E> c) {
        return delegate().drainTo(c);
    }

    private void checkUnsaturated() {
        if (delegate().size() < boundThreshold && isSaturated.get()) {
            if (isSaturated.compareAndSet(true, false)) {
                queueBoundObserver.onUnsaturated();
            }
        }
    }

    private void checkSaturated() {
        if ((delegate().size() >= boundCapacity) && !isSaturated.get()) {
            if (isSaturated.compareAndSet(false, true)) {
                queueBoundObserver.onSaturated();
            }
        }
    }
}