Thread pool with bounded queue

前端 未结 2 1302
一整个雨季
一整个雨季 2021-02-03 16:17

I have seen the thread pool executor implementation and the rejected execution policies that it provides. However, I have a custom requirement - I want to have a call back mecha

相关标签:
2条回答
  • 2021-02-03 17:01

    So here is the code that I have based on the answer above. The call to saturated and unSaturated needs to be invoked during sustained load on the worker queue of the thread pool and I believe the implementation achieves it by making use of non blocking algorithm.

    Also, this implementation can be used for any implementation of blocking queue (also the original queue could be bounded or unbounded).

    I am using guava's ForwardingBlockingQueue to write my decorator. Any suggestions would be greatly appreciated.

    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();
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-03 17:04

    I want to have a call back mechanism where in I get notifications when the queue size limit is reached...

    I wouldn't subclass the executor but I would subclass the BlockingQueue that is used by the executor. Something like the following should work. There are race conditions in the code around the checkUnsaturated() if you remove an entry and someone puts one back in. You might have to synchronize on the queue if these need to be perfect. Also, I have no idea what methods the executor implementations use so you might not need to override some of these.

    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();
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题