Consider a Swing application with a JList or JTable, when the selection changes a SwingWorker is started and loads related data from database and updates UI. This works fine and the UI is responsive.
But if the user is quickly changing the selected row (holding key-up/down) I want to be sure that the last selected row is the one that is loaded last, and also I don't wanna query the DB in vain. So what I want is an single threaded Executor with a LIFO queue of size=1. So submitting a task to it removes any previous submitted tasks and making it execute at most 1 task at a time and having at most 1 task waiting for execution.
I couldn't find anything like this in java.util.concurrent so I wrote my own Executor. Was I right in doing that or am I missing something from the concurrent package? Is the solution acceptable or is there better ways of achieving what I want?
public class SingleLIFOExecutor implements Executor
{
private final ThreadPoolExecutor executor;
private Runnable lastCommand;
public SingleLIFOExecutor()
{
executor = new ThreadPoolExecutor(0, 1, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1));
}
#Override
public void execute(Runnable command)
{
executor.remove(lastCommand);
lastCommand = command;
executor.execute(command);
}
}
And here's an example showing how it could be used:
final Executor executor = new SingleLIFOExecutor();
JList jList = createMyList();
jList.addListSelectionListener(new ListSelectionListener()
{
#Override
public void valueChanged(ListSelectionEvent e)
{
if (!e.getValueIsAdjusting())
{
executor.execute(new MyWorker());
}
}
});
LinkedBlockingDeque seems to still use Queues with ThreadPoolExecutor.
So instead I used a wrapper and used it with the ThreadPoolExecutor:
package util;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
/**
* LIFO BlockingQueue to be used with the ExecutorService.
* #author Daniel
* #param <T>
*/
public class LinkedBlockingStack<T> implements BlockingQueue<T>{
private final LinkedBlockingDeque<T> stack = new LinkedBlockingDeque<T>();
#Override
public T remove() {
return stack.remove();
}
#Override
public T poll() {
return stack.poll();
}
#Override
public T element() {
return stack.element();
}
#Override
public T peek() {
return stack.peek();
}
#Override
public int size() {
return stack.size();
}
#Override
public boolean isEmpty() {
return stack.isEmpty();
}
#Override
public Iterator<T> iterator() {
return stack.iterator();
}
#Override
public Object[] toArray() {
return stack.toArray();
}
#Override
public <S> S[] toArray(final S[] a) {
return stack.toArray(a);
}
#Override
public boolean containsAll(final Collection<?> c) {
return stack.containsAll(c);
}
#Override
public boolean addAll(final Collection<? extends T> c) {
return stack.addAll(c);
}
#Override
public boolean removeAll(final Collection<?> c) {
return stack.removeAll(c);
}
#Override
public boolean retainAll(final Collection<?> c) {
return stack.removeAll(c);
}
#Override
public void clear() {
stack.clear();
}
#Override
public boolean add(final T e) {
return stack.offerFirst(e); //Used offerFirst instead of add.
}
#Override
public boolean offer(final T e) {
return stack.offerFirst(e); //Used offerFirst instead of offer.
}
#Override
public void put(final T e) throws InterruptedException {
stack.put(e);
}
#Override
public boolean offer(final T e, final long timeout, final TimeUnit unit)
throws InterruptedException {
return stack.offerLast(e, timeout, unit);
}
#Override
public T take() throws InterruptedException {
return stack.take();
}
#Override
public T poll(final long timeout, final TimeUnit unit)
throws InterruptedException {
return stack.poll();
}
#Override
public int remainingCapacity() {
return stack.remainingCapacity();
}
#Override
public boolean remove(final Object o) {
return stack.remove(o);
}
#Override
public boolean contains(final Object o) {
return stack.contains(o);
}
#Override
public int drainTo(final Collection<? super T> c) {
return stack.drainTo(c);
}
#Override
public int drainTo(final Collection<? super T> c, final int maxElements) {
return stack.drainTo(c, maxElements);
}
}
BlockingDeque I believe is what you want. It supports stacks.
What I have in my code:
private transient final ExecutorService threadPool=
new ThreadPoolExecutor(3, 10,10,
TimeUnit.MILLISECONDS,
new LinkedBlockingDeque<Runnable>());
This was the solution I implemented, works great for the problem I tried to solve :)
/**
* A "Single Last-In-First-Out Executor".
* <p>
* It maintains a queue of <b>one</b> task and only one task may execute simultaneously,
* submitting a new task to {#link #execute(Runnable)} will discard any previous submitted not yet started tasks.
*/
public class SingleLIFOExecutor implements Executor
{
private final ThreadPoolExecutor executor;
private Runnable lastCommand;
public SingleLIFOExecutor()
{
executor = new ThreadPoolExecutor(0, 1, 0, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1));
}
/**
* #see java.util.concurrent.Executor#execute(java.lang.Runnable)
*/
#Override
public void execute(Runnable command)
{
executor.remove(lastCommand);
lastCommand = command;
executor.execute(command);
}
}
Related
I'm new to java.util.concurrent package therefore I'd like to ask an advice. I need to evaluate some operation within a ThreadPool, but I also need to cancel the concurrent evaluation. So, I tend to wrap the ThreadPoolExecutor into a Future<T> interface. Here is what I tried to do:
public class PooledFutureTask implements Future<List<Integer>> {
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
private boolean cancelled;
List<Integer> result;
public PooledFutureTask(List<Runnable> runnables) {
for (Runnable r : runnables)
executor.execute(r);
}
#Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (executor.shutdownNow().size() > 0)
return cancelled = true;
return executor.isTerminated() || executor.isShutdown();
}
#Override
public boolean isCancelled() {
return cancelled;
}
#Override
public boolean isDone() {
return executor.isTerminated();
}
#Override
public List<Integer> get() throws InterruptedException, ExecutionException {
while(true) {
if (executor.isShutdown())
return result;
}
}
#Override
public List<Integer> get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
if (executor.awaitTermination(timeout, TimeUnit.MILLISECONDS))
throw new TimeoutException();
return result;
}
}
But I'm not sure about that. Couldn't you point me out where I was wrong?
I'm using Java7.
I'm using ScheduledThreadPoolExecutor and I don't know hot to deal with something.
I'm scheduling some tasks this way:
scheduledExecService = new ExtendedScheduledExecutor(numThreads, myThreadFactory);
TareaActualizacion act = new TareaActualizacion(inst);
ScheduledFuture<?> handle = scheduledExecService.scheduleWithFixedDelay(act, retrasoInicial, segundosRefresco, TimeUnit.SECONDS);
act is a Runnable class that recive some data by parameter:
public class TareaActualizacion implements Runnable {
private Instalacion instalacion;
public TareaActualizacion(Instalacion instalacion) {
this.instalacion = instalacion;
}
#Override
public void run() {
//Do something
}
public Instalacion getInstalacion() {
return instalacion;
}
}
Now in the afterExecute method of the ExtendedSecheduledExecutor I want to get the object Instalacion of the task TareaActualizacion but I don't know how to do it.
My ExtendedScheduledExecutor class looks like this:
public class ExtendedScheduledExecutor extends ScheduledThreadPoolExecutor{
public ExtendedScheduledExecutor(int arg0) {
super(arg0);
}
public ExtendedScheduledExecutor(int arg0, ThreadFactory arg1) {
super(arg0, arg1);
}
#Override
protected void afterExecute(Runnable r, Throwable t)
{
super.afterExecute(r, t);
System.out.println("Executing afterExecute. Throwable is " + t);
if (t != null)
t.printStackTrace();
//I need to get the Instalacion attribute from TareaActualizacion task. How can I do it??
}
}
Any idea of how can I solve it??
Thank you!
Neus
As Stephan already pointed out in https://stackoverflow.com/a/22145530 , you should try to decouple the scheduling and execution from the notification.
One approach for this could be to wrap the actual task (TareaActualizacion) into another implementation of the Runnable interface that only executes the actual task, and afterwards notifies a callback about the task that has been executed.
Depending on your precise requirements, there may be several degrees of freedom for the implementation, but a general approach could roughly look like this:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledTaskNotification
{
public static void main(String[] args) throws Exception
{
ScheduledExecutorService executor = Executors.newScheduledThreadPool(4);
int n = 3;
for (int i = 0; i < n; i++)
{
UpdateTask updateTask = new UpdateTask(i);
RunnableCallback<UpdateTask> callback = new RunnableCallback<UpdateTask>()
{
#Override
public void runnableFinished(UpdateTask updateTask)
{
System.out.println("Finished "+updateTask+", id "+updateTask.getID());
}
};
Runnable runnableWithCallback =
createRunnableWithCallback(updateTask, callback);
executor.scheduleWithFixedDelay(
runnableWithCallback, 1000, 200+i*200,
TimeUnit.MILLISECONDS);
}
}
static interface RunnableCallback<T extends Runnable>
{
void runnableFinished(T runnable);
}
private static <T extends Runnable> Runnable createRunnableWithCallback(
final T runnable, final RunnableCallback<T> callback)
{
return new Runnable()
{
#Override
public void run()
{
runnable.run();
callback.runnableFinished(runnable);
}
};
}
private static class UpdateTask implements Runnable
{
private final int id;
UpdateTask(int id)
{
this.id = id;
}
#Override
public void run()
{
System.out.println("Run "+this);
}
int getID()
{
return id;
}
#Override
public String toString()
{
return "UpdateTask "+id;
}
}
}
This is a bay way. You should not trying to get the result out of the Executor, because it is only responsible for scheduling and executing tasks, not whats happening inside of them.
Your TareaActualizacion runnable should post the result to another piece of code, where you need it. This can be achieved using a queue or in the easiest case SwingUtilities.invokeLater().
ThreadPoolExecutor doc says
If corePoolSize or more threads are running, the Executor always
prefers queuing a request rather than adding a new thread.
If there are more than corePoolSize but less than maximumPoolSize
threads running, a new thread will be created only if the queue is
full.
Is there a way to get the executor to prefer new thread creation until the max is reached even if there are there are more than core size threads, and then start queuing? Tasks would get rejected if the queue reached its maximum size. It would be nice if the timeout setting would kick in and remove threads down to core size after a busy burst has been handled. I see the reason behind preferring to queue so as to allow for throttling; however, this customization would additionally allow the queue to act mainly as a list of tasks yet to be run.
No way to get this exact behavior with a ThreadPoolExecutor.
But, here's a couple solutions:
Consider,
If less than corePoolSize threads are running, a new thread will be created for every item queued until coorPoolSize threads are running.
A new thread will only be created if the queue is full, and less than maximumPoolSize threads are running.
So, wrap a ThreadPoolExecutor in a class which monitors how fast items are being queued. Then, change the core pool size to a higher value when many items are being submitted. This will cause a new thread to be created each time a new item is submitted.
When the submission burst is done, core pool size needs to be manually reduced again so the threads can naturally time out. If you're worried the busy burst could end abruptly, causing the manual method to fail, be sure to use allowCoreThreadTimeout.
Create a fixed thread pool, and allowCoreThreadTimeout
Unfortunately this uses more threads during low submission bursts, and stores no idle threads during zero traffic.
Use the 1st solution if you have the time, need, and inclination as it will handle a wider range of submission frequency and so is a better solution in terms of flexibility.
Otherwise use the 2nd solution.
Just do what Executors.newFixedThreadPool does and set core and max to the same value. Here's the newFixedThreadPool source from Java 6:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
What you can do if you have an existing one:
ThreadPoolExecutor tpe = ... ;
tpe.setCorePoolSize(tpe.getMaxPoolSize());
Edit: As William points out in the comments, this means that all threads are core threads, so none of the threads will time out and terminate. To change this behavior, just use ThreadPoolExecutor.allowCoreThreadTimeout(true). This will make it so that the threads can time out and be swept away when the executor isn't in use.
It seems that your preference is minimal latency during times of low-activity. For that I would just set the corePoolSize to the max and let the extra threads hang around. During high-activity times these threads will be there anyways. During low-activity times their existence won't have that much impact. You can set the core thread timeout if you want them to die though.
That way all the threads will always be available to execute a task as soon as possible.
CustomBlockingQueue
package com.gunjan;
import java.util.concurrent.BlockingQueue;
public abstract class CustomBlockingQueue<E> implements BlockingQueue<E> {
public BlockingQueue<E> blockingQueue;
public CustomBlockingQueue(BlockingQueue blockingQueue) {
this.blockingQueue = blockingQueue;
}
#Override
final public boolean offer(E e) {
return false;
}
final public boolean customOffer(E e) {
return blockingQueue.offer(e);
}
}
ThreadPoolBlockingQueue
package com.gunjan;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
public class ThreadPoolBlockingQueue<E> extends CustomBlockingQueue<E> {
public ThreadPoolBlockingQueue(BlockingQueue blockingQueue) {
super(blockingQueue);
}
#Override
public E remove() {
return this.blockingQueue.remove();
}
#Override
public E poll() {
return this.blockingQueue.poll();
}
#Override
public E element() {
return this.blockingQueue.element();
}
#Override
public E peek() {
return this.blockingQueue.peek();
}
#Override
public int size() {
return this.blockingQueue.size();
}
#Override
public boolean isEmpty() {
return this.blockingQueue.isEmpty();
}
#Override
public Iterator<E> iterator() {
return this.blockingQueue.iterator();
}
#Override
public Object[] toArray() {
return this.blockingQueue.toArray();
}
#Override
public <T> T[] toArray(T[] a) {
return this.blockingQueue.toArray(a);
}
#Override
public boolean containsAll(Collection<?> c) {
return this.blockingQueue.containsAll(c);
}
#Override
public boolean addAll(Collection<? extends E> c) {
return this.blockingQueue.addAll(c);
}
#Override
public boolean removeAll(Collection<?> c) {
return this.blockingQueue.removeAll(c);
}
#Override
public boolean retainAll(Collection<?> c) {
return this.blockingQueue.retainAll(c);
}
#Override
public void clear() {
this.blockingQueue.clear();
}
#Override
public boolean add(E e) {
return this.blockingQueue.add(e);
}
#Override
public void put(E e) throws InterruptedException {
this.blockingQueue.put(e);
}
#Override
public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
return this.blockingQueue.offer(e, timeout, unit);
}
#Override
public E take() throws InterruptedException {
return this.blockingQueue.take();
}
#Override
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
return this.blockingQueue.poll(timeout, unit);
}
#Override
public int remainingCapacity() {
return this.blockingQueue.remainingCapacity();
}
#Override
public boolean remove(Object o) {
return this.blockingQueue.remove(o);
}
#Override
public boolean contains(Object o) {
return this.blockingQueue.contains(o);
}
#Override
public int drainTo(Collection<? super E> c) {
return this.blockingQueue.drainTo(c);
}
#Override
public int drainTo(Collection<? super E> c, int maxElements) {
return this.blockingQueue.drainTo(c, maxElements);
}
}
RejectedExecutionHandlerImpl
package com.gunjan;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
public class RejectedExecutionHandlerImpl implements RejectedExecutionHandler {
#Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
boolean inserted = ((CustomBlockingQueue) executor.getQueue()).customOffer(r);
if (!inserted) {
throw new RejectedExecutionException();
}
}
}
CustomThreadPoolExecutorTest
package com.gunjan;
import java.util.concurrent.*;
public class CustomThreadPoolExecutorTest {
public static void main(String[] args) throws InterruptedException {
LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<Runnable>(500);
CustomBlockingQueue customLinkedBlockingQueue = new ThreadPoolBlockingQueue<Runnable>(linkedBlockingQueue);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 100, 60, TimeUnit.SECONDS,
customLinkedBlockingQueue, new RejectedExecutionHandlerImpl());
for (int i = 0; i < 750; i++) {
try {
threadPoolExecutor.submit(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
System.out.println(threadPoolExecutor);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
} catch (RejectedExecutionException e) {
e.printStackTrace();
}
}
threadPoolExecutor.shutdown();
threadPoolExecutor.awaitTermination(Integer.MAX_VALUE, TimeUnit.MINUTES);
System.out.println(threadPoolExecutor);
}
}
which one should I choose over another among these programs and why? Generally the question is why should I choose to use PriorityBlockingQueue over PriorityQueue.
PriorityBlockingQueue
import java.util.concurrent.PriorityBlockingQueue;
public class PriorityBlockingQueueExample {
static PriorityBlockingQueue<String> priorityQueue = new PriorityBlockingQueue<String>();
public static void main(String[] args) {
new Thread(){
public void run(){
try {
System.out.println(priorityQueue.take() +" is removed from priorityQueue object");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
new Thread(){
public void run(){
priorityQueue.add("string variable");
System.out.println("Added an element to the queue");
}
}.start();
}
}
which one should I choose over another among these programs and why? Generally the question is why should I choose to use PriorityBlockingQueue over PriorityQueue.
PriorityQueue
import java.util.PriorityQueue;
public class PriorityQueueTest {
static PriorityQueue<String> priorityQueue = new PriorityQueue<String>();
private static Object lock = new Object();
public static void main(String[] args) {
new Thread(){
public void run(){
synchronized(lock){
try {
while(priorityQueue.isEmpty()){lock.wait();}
System.out.println(priorityQueue.remove() +" is removed from priorityQueue object");
lock.notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
new Thread(){
public void run(){
synchronized(lock){
priorityQueue.add("string variable");
System.out.println("Added an element to the queue");
lock.notify();
}
}
}.start();
}
}
A normal Queue will return null when accessed if it is empty, while a BlockingQueue blocks if the queue is empty until a value is available.
The priority part in the queues you are using simply means the items are read from the queue in a specific order (either natural if they implement Comparable or according to a Comparator).
Typically you could should depend on the abstract type, either PriorityQueue or BlockingQueue. If your code requires knowledge of both these concepts a re-think may be needed.
There's numerous reasons why you might need a PriorityQueue that boil down to message ordering. For example on a queue of jobs, you might want to be able to give those jobs priority. That said typically the code processing the jobs should be agnostic to the order.
With a BlockingQueue you're typically in the realm of worker threads picking up queued work and when there's no work to do, those threads can be blocked until work becomes available. Like the example of a PriorityQueue, the calling code could be agnostic to this, though as you may want to use some sort of wait timeout that's not always case.
PriorityBlockingQueue was added with the concurrent package in JDK 5 see: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/package-summary.html
It's basically under the hood doing the extra code you wrote for PriorityQueue of adding the commonly necessary synchronize/wait/notify around your queue. Thus the "Blocking" part of the name is added to imply the thread will block waiting until there's an item available on the queue.
If your app can run on JDK 5 or newer, I'd use PriorityBlockingQueue.
I know that this is an old topic but I saw that you didnt consider a concurrent implementation of a priority queue.
Although java's collections framework does not have one, it does have enough building blocks to create one:
public class ConcurrentSkipListPriorityQueue<T> implements Queue<T> {
private ConcurrentSkipListMap<T, Boolean> values;
public ConcurrentSkipListPriorityQueue(Comparator<? super T> comparator) {
values = new ConcurrentSkipListMap<>(comparator);
}
public ConcurrentSkipListPriorityQueue() {
values = new ConcurrentSkipListMap<>();
}
#Override
public boolean add(T e) {
values.put(e, Boolean.TRUE);
return true;
}
#Override
public boolean offer(T e) {
return add(e);
}
#Override
public T remove() {
while (true) {
final T v = values.firstKey();
if (values.remove(v)) {
return v;
}
}
}
#Override
public T poll() {
try {
while (true) {
if (values.isEmpty()) {
return null;
}
final T v = values.firstKey();
if (values.remove(v)) {
return v;
}
}
} catch (NoSuchElementException ex) {
return null; // poll should not throw an exception..
}
}
#Override
public T element() {
return values.firstKey();
}
#Override
public T peek() {
if (values.isEmpty()) {
return null;
}
try {
return element();
} catch (NoSuchElementException ex) {
return null;
}
}
#Override
public int size() {
return values.size();
}
#Override
public boolean isEmpty() {
return values.isEmpty();
}
#Override
public boolean contains(Object o) {
return values.containsKey(o);
}
#Override
public Iterator<T> iterator() {
return values.keySet().iterator();
}
#Override
public Object[] toArray() {
return values.keySet().toArray();
}
#Override
public <T> T[] toArray(T[] a) {
return values.keySet().toArray(a);
}
#Override
public boolean remove(Object o) {
return values.remove(o);
}
#Override
public boolean containsAll(Collection<?> c) {
return values.keySet().containsAll(c);
}
#Override
public boolean addAll(Collection<? extends T> c) {
boolean changed = false;
for (T i : c) {
changed |= add(i);
}
return changed;
}
#Override
public boolean removeAll(Collection<?> c) {
return values.keySet().removeAll(c);
}
#Override
public boolean retainAll(Collection<?> c) {
return values.keySet().retainAll(c);
}
#Override
public void clear() {
values.clear();
}
}
This queue is based on skip list by delegating all of its operations to the ConcurrentSkipListMap class. It allows non-blocking concurrent access from multiple threads.
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 mechanism where in I get notifications when the queue size limit is reached and say when the queue size reduces to say 80 % of the max allowed queue size.
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.
}
I feel that this can be implemented by subclassing thread pool executor, but is there an already implemented version? I would be happy to add more details and my work so far as and when needed to provide clarity.
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();
}
}
}
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();
}
}
}
}