/**
* The utillib library.
* More information is available at http://www.jinchess.com/.
* Copyright (C) 2002 Alexander Maryanovsky.
* All rights reserved.
*
* The utillib 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 2 of the
* License, or (at your option) any later version.
*
* The utillib 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 utillib library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.util.Enumeration;
import java.util.Vector;
/**
* A blocking queue, one that always "contains" elements.
* If it is in fact empty, the pop() and peek() method will block until an
* item is pushed.
*
NOTE: This class is thread safe.
*
* @author Alexander Maryanovsky.
*/
public class BlockingQueue implements Cloneable{
/**
* The underlying Vector this BlockingQueue is using.
*/
private final Vector queue;
/**
* The lock we use to synchronize pushing.
*/
private final Object pushLock = new String("BlockingQueue pushLock");
/**
* The lock we use to synchronize popping.
*/
private final Object popLock = new String("BlockingQueue popLock");
/**
* Creates a new, empty BlockingQueue.
*/
public BlockingQueue(){
queue = new Vector();
}
/**
* Pushes an element into the queue.
*/
public void push(Object object){
synchronized(pushLock){
queue.addElement(object);
synchronized(this){
notify();
}
}
}
/**
* Pops an element from the queue. If the queue is empty, this method blocks
* until another thread pushes an element into the queue.
*
* @throws InterruptedException if the invoking thread was interrupted
* while waiting for an element to be pushed into the queue.
*/
public Object pop() throws InterruptedException{
return pop(0);
}
/**
* Pops an element from the queue. Unlike the pop() method, this method does not block
* for longer than the given amount of milliseconds. When the given amount of milliseconds
* have passed, this method will throw an InterruptedException.
*/
public Object pop(long timeout) throws InterruptedException{
synchronized(popLock){
synchronized(this){
if (queue.isEmpty()){
wait(timeout);
if (queue.isEmpty())
throw new InterruptedException("Timed out");
}
}
Object val = queue.firstElement();
queue.removeElementAt(0);
return val;
}
}
/**
* Returns the element on top of the queue without popping it. If the queue
* is empty, this method blocks until another thread pushes an element into
* the queue.
*
* @throws InterruptedException if the invoking thread was interrupted while
* waiting for an element to be pushed into the queue.
*/
public Object peek() throws InterruptedException{
return peek(0);
}
/**
* Returns the element on top of the queue without popping it.
* Unlike the peek() method, this method does not block
* for longer than the given amount of milliseconds. When the given amount of milliseconds
* have passed, this method will throw an InterruptedException.
*/
public Object peek(long timeout) throws InterruptedException{
synchronized(popLock){
synchronized(this){
if (queue.isEmpty()){
wait(timeout);
if (queue.isEmpty())
throw new InterruptedException("Timed out");
}
}
return queue.firstElement();
}
}
/**
* Returns true if the queue is empty (this returns the actual state of the
* queue, meaning it may return true even though ideologically, a BlockingQueue
* is never empty).
*/
public boolean isEmpty(){
return queue.isEmpty();
}
/**
* Returns true if the given element is in the queue.
*/
public boolean contains(Object element){
return queue.contains(element);
}
/**
* Returns the size of the queue.
*/
public int size(){
return queue.size();
}
/**
* Returns an Enumeration of the elements in this queue. The order of the
* elements is the same as if they were popped from the queue one by one (the
* first element is the first element that would have been popped).
* IMPORTANT: Modifying the queue breaks the returned Enumeration.
*/
public Enumeration getElements(){
return queue.elements();
}
/**
* Removes all elements from this queue.
*/
public void removeAllElements(){
queue.removeAllElements();
}
/**
* Removes all elements from this queue.
*/
public void clear(){
queue.removeAllElements();
}
/**
* Returns a shallow copy of this BlockingQueue.
*/
public synchronized Object clone(){
BlockingQueue copy = new BlockingQueue();
Enumeration elems = getElements();
while (elems.hasMoreElements()){
Object item = elems.nextElement();
copy.push(item);
}
return copy;
}
}