27691: Adding timeout versions of get() and remove()

git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk@170761 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
James W. Carman 2005-05-18 15:03:02 +00:00
parent e297d23839
commit 61173f58aa
2 changed files with 87 additions and 23 deletions

View File

@ -25,35 +25,35 @@ import org.apache.commons.collections.BufferUnderflowException;
/** /**
* Decorates another <code>Buffer</code> to make {@link #get()} and * Decorates another <code>Buffer</code> to make {@link #get()} and
* {@link #remove()} block when the <code>Buffer</code> is empty. * {@link #remove()} block when the <code>Buffer</code> is empty.
* <p> * <p/>
* If either <code>get</code> or <code>remove</code> is called on an empty * If either <code>get</code> or <code>remove</code> is called on an empty
* <code>Buffer</code>, the calling thread waits for notification that * <code>Buffer</code>, the calling thread waits for notification that
* an <code>add</code> or <code>addAll</code> operation has completed. * an <code>add</code> or <code>addAll</code> operation has completed.
* <p> * <p/>
* When one or more entries are added to an empty <code>Buffer</code>, * When one or more entries are added to an empty <code>Buffer</code>,
* all threads blocked in <code>get</code> or <code>remove</code> are notified. * all threads blocked in <code>get</code> or <code>remove</code> are notified.
* There is no guarantee that concurrent blocked <code>get</code> or * There is no guarantee that concurrent blocked <code>get</code> or
* <code>remove</code> requests will be "unblocked" and receive data in the * <code>remove</code> requests will be "unblocked" and receive data in the
* order that they arrive. * order that they arrive.
* <p> * <p/>
* This class is Serializable from Commons Collections 3.1. * This class is Serializable from Commons Collections 3.1.
* *
* @since Commons Collections 3.0
* @version $Revision$ $Date$
*
* @author Stephen Colebourne * @author Stephen Colebourne
* @author Janek Bogucki * @author Janek Bogucki
* @author Phil Steitz * @author Phil Steitz
* @version $Revision$ $Date$
* @since Commons Collections 3.0
*/ */
public class BlockingBuffer extends SynchronizedBuffer { public class BlockingBuffer extends SynchronizedBuffer {
/**
/** Serialization version */ * Serialization version
*/
private static final long serialVersionUID = 1719328905017860541L; private static final long serialVersionUID = 1719328905017860541L;
/** /**
* Factory method to create a blocking buffer. * Factory method to create a blocking buffer.
* *
* @param buffer the buffer to decorate, must not be null * @param buffer the buffer to decorate, must not be null
* @return a new blocking Buffer * @return a new blocking Buffer
* @throws IllegalArgumentException if buffer is null * @throws IllegalArgumentException if buffer is null
*/ */
@ -64,8 +64,8 @@ public class BlockingBuffer extends SynchronizedBuffer {
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
/** /**
* Constructor that wraps (not copies). * Constructor that wraps (not copies).
* *
* @param buffer the buffer to decorate, must not be null * @param buffer the buffer to decorate, must not be null
* @throws IllegalArgumentException if the buffer is null * @throws IllegalArgumentException if the buffer is null
*/ */
protected BlockingBuffer(Buffer buffer) { protected BlockingBuffer(Buffer buffer) {
@ -74,7 +74,7 @@ public class BlockingBuffer extends SynchronizedBuffer {
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
public boolean add(Object o) { public boolean add(Object o) {
synchronized (lock) { synchronized(lock) {
boolean result = collection.add(o); boolean result = collection.add(o);
notifyAll(); notifyAll();
return result; return result;
@ -82,7 +82,7 @@ public class BlockingBuffer extends SynchronizedBuffer {
} }
public boolean addAll(Collection c) { public boolean addAll(Collection c) {
synchronized (lock) { synchronized(lock) {
boolean result = collection.addAll(c); boolean result = collection.addAll(c);
notifyAll(); notifyAll();
return result; return result;
@ -90,11 +90,12 @@ public class BlockingBuffer extends SynchronizedBuffer {
} }
public Object get() { public Object get() {
synchronized (lock) { synchronized(lock) {
while (collection.isEmpty()) { while(collection.isEmpty()) {
try { try {
wait(); wait();
} catch (InterruptedException e) { }
catch(InterruptedException e) {
PrintWriter out = new PrintWriter(new StringWriter()); PrintWriter out = new PrintWriter(new StringWriter());
e.printStackTrace(out); e.printStackTrace(out);
throw new BufferUnderflowException("Caused by InterruptedException: " + out.toString()); throw new BufferUnderflowException("Caused by InterruptedException: " + out.toString());
@ -104,12 +105,35 @@ public class BlockingBuffer extends SynchronizedBuffer {
} }
} }
public Object get(final long timeout) {
synchronized(lock) {
final long expiration = System.currentTimeMillis() + timeout;
long timeLeft = expiration - System.currentTimeMillis();
while(timeLeft > 0 && collection.isEmpty()) {
try {
wait(timeLeft);
timeLeft = expiration - System.currentTimeMillis();
}
catch(InterruptedException e) {
PrintWriter out = new PrintWriter(new StringWriter());
e.printStackTrace(out);
throw new BufferUnderflowException("Caused by InterruptedException: " + out.toString());
}
}
if(collection.isEmpty()) {
throw new BufferUnderflowException("Timeout expired.");
}
return getBuffer().get();
}
}
public Object remove() { public Object remove() {
synchronized (lock) { synchronized(lock) {
while (collection.isEmpty()) { while(collection.isEmpty()) {
try { try {
wait(); wait();
} catch (InterruptedException e) { }
catch(InterruptedException e) {
PrintWriter out = new PrintWriter(new StringWriter()); PrintWriter out = new PrintWriter(new StringWriter());
e.printStackTrace(out); e.printStackTrace(out);
throw new BufferUnderflowException("Caused by InterruptedException: " + out.toString()); throw new BufferUnderflowException("Caused by InterruptedException: " + out.toString());
@ -119,4 +143,25 @@ public class BlockingBuffer extends SynchronizedBuffer {
} }
} }
public Object remove(final long timeout) {
synchronized(lock) {
final long expiration = System.currentTimeMillis() + timeout;
long timeLeft = expiration - System.currentTimeMillis();
while(timeLeft > 0 && collection.isEmpty()) {
try {
wait(timeLeft);
timeLeft = expiration - System.currentTimeMillis();
}
catch(InterruptedException e) {
PrintWriter out = new PrintWriter(new StringWriter());
e.printStackTrace(out);
throw new BufferUnderflowException("Caused by InterruptedException: " + out.toString());
}
}
if(collection.isEmpty()) {
throw new BufferUnderflowException("Timeout expired.");
}
return getBuffer().remove();
}
}
} }

View File

@ -364,7 +364,26 @@ public class TestBlockingBuffer extends AbstractTestObject {
} }
} }
public void testTimeoutGet() {
final BlockingBuffer buffer = new BlockingBuffer(new MyBuffer());
try {
buffer.get( 100 );
fail( "Get should have timed out." );
}
catch( BufferUnderflowException e ){
}
}
public void testTimeoutRemove() {
final BlockingBuffer buffer = new BlockingBuffer(new MyBuffer());
try {
buffer.remove( 100 );
fail( "Get should have timed out." );
}
catch( BufferUnderflowException e ){
}
}
protected static class DelayedAdd extends Thread { protected static class DelayedAdd extends Thread {
Buffer buffer; Buffer buffer;