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
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 the type of elements held in this blocking queue.
*/
public class BoundObservableBlockingQueue extends ForwardingBlockingQueue {
/** observer to receive callbacks. */
private final ISaturatedQueueObserver queueBoundObserver;
/** original blocking queue being decorated. */
private final BlockingQueue 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 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 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();
}
}
}
}