/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; If not, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.core.collections.queues; import java.util.NoSuchElementException; /** * A ThreadsafeQueue can be used by different threads that * use this queue for communicating with each other. * If the queue is empty, the queue has to wait until * a different thread writes something into the queue. * This class can also be used as a bounded buffer! * <p> * This class is used by ThreadedIterator.</p> * <p> * Usage example (1). * <pre> * // create a threadsafe array queue * * Queue<Integer> queue = new ThreadsafeQueue<Integer>(new BoundedQueue<Integer>(new ArrayQueue<Integer>(),100)); * * // open the queue * * queue.open(); * * // create an enumeration with 100 elements * * Cursor<Integer> cursor = new Enumerator(100); * * // insert all elements in the queue * * for (; cursor.hasNext(); queue.enqueue(cursor.next())); * * System.out.println("There were "+queue.size()+" elements in the queue"); * * // close the queue and the cursor * * queue.close(); * cursor.close(); * </pre> * * @param <E> the type of the elements of this queue. * @see xxl.core.collections.queues.Queue * @see xxl.core.collections.queues.DecoratorQueue */ public class ThreadsafeQueue<E> extends DecoratorQueue<E> { /** Counts the number of failed calls to the underlying queue because the queue was full. */ public int failedCallsFull = 0; /** Counts the number of failed calls to the underlying queue because the queue was empty. */ public int failedCallsEmpty = 0; /** Counts the number of threads which want to insert into the queue. */ protected int countWaitForInsert = 0; /** Counts the number of threads which want to get an object out of the queue. */ protected int countWaitForNext = 0; /** Internal state constant. */ protected static final int EMPTY=0; /** Internal state constant. */ protected static final int NORMAL=1; /** Internal state constant. */ protected static final int FULL=2; /** Internal state of the queue. */ protected int state = EMPTY; /** * Constructs a threadsafe Queue. * * @param queue the queue that becomes threadsafe. */ public ThreadsafeQueue(Queue<E> queue) { super(queue); } /** * Appends the specified element to the <i>end</i> of this queue. The * <i>end</i> of the queue is given by its <i>strategy</i>. * * @param object element to be appended to the <i>end</i> of this * queue. */ public synchronized void enqueue(E object) { while (true) { if (state == FULL) { countWaitForInsert++; try { wait(); } catch (java.lang.InterruptedException e) { e.printStackTrace(); } countWaitForInsert--; } else { try { super.enqueue(object); // if (state == EMPTY) state=NORMAL; break; } catch (IndexOutOfBoundsException e) { failedCallsFull++; state = FULL; } } } if ((countWaitForNext > 0) || (countWaitForInsert > 0)) notify(); } /** * Returns the <i>next</i> element in the queue and <i>removes</i> it. * The <i>next</i> element of the queue is given by its <i>strategy</i>. * * @return the <i>next</i> element in the queue. */ public synchronized E dequeue() { E object; while (true) { if (state == EMPTY) { countWaitForNext++; try { wait(); } catch (java.lang.InterruptedException e) {} countWaitForNext--; } else { try { if (queue.size() > 0) { // equivalent to if (hasNext()) { object = super.dequeue(); //if (state == FULL) state = NORMAL; break; } } catch (NoSuchElementException e) {} // no element availlable here! failedCallsEmpty++; state = EMPTY; } } if ((countWaitForNext > 0) || (countWaitForInsert > 0)) notify(); return object; } }