You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ps...@apache.org on 2003/09/18 05:28:28 UTC
cvs commit: jakarta-commons/collections/src/test/org/apache/commons/collections/decorators TestBlockingBuffer.java
psteitz 2003/09/17 20:28:28
Modified: collections/src/java/org/apache/commons/collections/decorators
BlockingBuffer.java
collections/src/test/org/apache/commons/collections/decorators
TestBlockingBuffer.java
Log:
Modified BlockingBuffer add method to notifyAll
instead of notify.
Added tests to verify blocking behavior.
Patch submitted by: Janek Bogucki
Reviewed by: Phil Steitz
Pr #23232, 23159
Revision Changes Path
1.3 +5 -4 jakarta-commons/collections/src/java/org/apache/commons/collections/decorators/BlockingBuffer.java
Index: BlockingBuffer.java
===================================================================
RCS file: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/decorators/BlockingBuffer.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- BlockingBuffer.java 31 Aug 2003 17:24:46 -0000 1.2
+++ BlockingBuffer.java 18 Sep 2003 03:28:28 -0000 1.3
@@ -64,13 +64,14 @@
/**
* <code>BlockingBuffer</code> decorates another <code>Buffer</code>
- * to block on calls to the get method to wait until entries are
+ * to block on calls to the get and remove methods to wait until entries are
* added to the buffer.
*
* @since Commons Collections 3.0
* @version $Revision$ $Date$
*
* @author Stephen Colebourne
+ * @author Janek Bogucki
*/
public class BlockingBuffer extends SynchronizedBuffer {
@@ -98,7 +99,7 @@
public boolean add(Object o) {
synchronized (lock) {
boolean result = collection.add(o);
- notify();
+ notifyAll();
return result;
}
}
1.2 +181 -77 jakarta-commons/collections/src/test/org/apache/commons/collections/decorators/TestBlockingBuffer.java
Index: TestBlockingBuffer.java
===================================================================
RCS file: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/decorators/TestBlockingBuffer.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- TestBlockingBuffer.java 15 Sep 2003 03:50:41 -0000 1.1
+++ TestBlockingBuffer.java 18 Sep 2003 03:28:28 -0000 1.2
@@ -57,15 +57,16 @@
*/
package org.apache.commons.collections.decorators;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedList;
-import java.util.ArrayList;
+import java.util.Set;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.apache.commons.collections.Buffer;
-import org.apache.commons.collections.ArrayStack;
import org.apache.commons.collections.BufferUnderflowException;
import org.apache.commons.collections.decorators.BlockingBuffer;
@@ -102,7 +103,7 @@
//-----------------------------------------------------------------------
/**
- * Tests {@link BlockingBuffer#get()}.
+ * Tests {@link BlockingBuffer#get()} in combination with {@link BlockingBuffer#add()}.
*/
public void testGetWithAdd() {
@@ -117,7 +118,7 @@
//-----------------------------------------------------------------------
/**
- * Tests {@link BlockingBuffer#get()}.
+ * Tests {@link BlockingBuffer#get()} in combination with {@link BlockingBuffer#addAll()}.
*/
public void testGetWithAddAll() {
@@ -132,7 +133,7 @@
//-----------------------------------------------------------------------
/**
- * Tests {@link BlockingBuffer#remove()}.
+ * Tests {@link BlockingBuffer#remove()} in combination with {@link BlockingBuffer#add()}.
*/
public void testRemoveWithAdd() {
@@ -147,7 +148,7 @@
//-----------------------------------------------------------------------
/**
- * Tests {@link BlockingBuffer#remove()}.
+ * Tests {@link BlockingBuffer#remove()} in combination with {@link BlockingBuffer#addAll()}.
*/
public void testRemoveWithAddAll() {
@@ -159,107 +160,74 @@
// verify does not throw BufferUnderflowException; should block until other thread has added to the buffer .
assertSame(obj, blockingBuffer.remove());
}
-
+
//-----------------------------------------------------------------------
/**
- * Tests get using multiple read threads.
+ * Tests {@link BlockingBuffer#get()} in combination with {@link BlockingBuffer#add()} using multiple read threads.
*
- * Verifies that multiple adds are required to allow gets by
- * multiple threads on an empty buffer to complete.
+ * Two read threads should block on an empty buffer until one object
+ * is added then both threads should complete.
*/
public void testBlockedGetWithAdd() {
Buffer blockingBuffer = BlockingBuffer.decorate(new MyBuffer());
Object obj = new Object();
- // run methods will get and compare -- must wait for adds
+ // run methods will get and compare -- must wait for add
Thread thread1 = new ReadThread(blockingBuffer, obj);
Thread thread2 = new ReadThread(blockingBuffer, obj);
thread1.start();
thread2.start();
// give hungry read threads ample time to hang
- try {
- Thread.currentThread().sleep(100);
- } catch (InterruptedException e) {}
+ delay();
- // notify should allow one read thread to complete
+ // notifyAll should allow both read threads to complete
blockingBuffer.add(obj);
- // allow notified thread(s) to complete
- try {
- Thread.currentThread().sleep(100);
- } catch (InterruptedException e) {}
+ // allow notified threads to complete
+ delay();
- // There shoould still be one thread waiting. Verify this.
- // This check will fail if add is changed to notifyAll.
- assertTrue("One read thread should be waiting",
- thread1.isAlive() || thread2.isAlive());
-
- // now add again so the second thread will be notified
- blockingBuffer.add(obj);
-
- // wait to exit until both threads are dead, or appear to be hung
- boolean finished = false;
- for (int i = 1; i < 10; i++) {
- if (thread1.isAlive() || thread2.isAlive()) {
- try {
- Thread.currentThread().sleep(100);
- }
- catch (InterruptedException e) {}
- } else {
- finished = true;
- break;
- }
- }
- if (!finished) {
- fail("Read thread did not finish.");
- }
+ // There should not be any threads waiting.
+ if (thread1.isAlive() || thread2.isAlive())
+ fail("Live thread(s) when both should be dead.");
}
+ //-----------------------------------------------------------------------
/**
- * Tests get using multiple read threads.
- * Shows that one addAll allows multiple gets to complete.
+ * Tests {@link BlockingBuffer#get()} in combination with {@link BlockingBuffer#addAll()} using multiple read threads.
+ *
+ * Two read threads should block on an empty buffer until a
+ * singleton is added then both threads should complete.
*/
public void testBlockedGetWithAddAll() {
Buffer blockingBuffer = BlockingBuffer.decorate(new MyBuffer());
Object obj = new Object();
- // run methods will get and compare -- must wait for adds
+ // run methods will get and compare -- must wait for addAll
Thread thread1 = new ReadThread(blockingBuffer, obj);
Thread thread2 = new ReadThread(blockingBuffer, obj);
thread1.start();
thread2.start();
// give hungry read threads ample time to hang
- try {
- Thread.currentThread().sleep(100);
- } catch (InterruptedException e) {}
+ delay();
// notifyAll should allow both read threads to complete
blockingBuffer.addAll(Collections.singleton(obj));
- // wait to exit until both threads are dead, or appear to be hung
- boolean finished = false;
- for (int i = 1; i < 10; i++) {
- if (thread1.isAlive() || thread2.isAlive()) {
- try {
- Thread.currentThread().sleep(100);
- }
- catch (InterruptedException e) {}
- } else {
- finished = true;
- break;
- }
- }
- if (!finished) {
- fail("Read thread did not finish.");
- }
+ // allow notified threads to complete
+ delay();
+
+ // There should not be any threads waiting.
+ if (thread1.isAlive() || thread2.isAlive())
+ fail("Live thread(s) when both should be dead.");
}
+ //-----------------------------------------------------------------------
/**
- * Tests interrupted get.
+ * Tests interrupted {@link BlockingBuffer#get()}.
*/
public void testInterruptedGet() {
@@ -275,19 +243,140 @@
thread.interrupt();
// Chill, so thread can throw and add message to exceptionList
- try {
- Thread.currentThread().sleep(100);
- } catch (InterruptedException e) {}
+ delay();
assertTrue("Thread interrupt should have led to underflow",
exceptionList.contains("BufferUnderFlow"));
if (thread.isAlive()) {
- fail("Hung read thread");
+ fail("Read thread has hung.");
}
}
+ //-----------------------------------------------------------------------
+ /**
+ * Tests {@link BlockingBuffer#remove()} in combination with {@link BlockingBuffer#add()} using multiple read threads.
+ *
+ * Two read threads should block on an empty buffer until one
+ * object is added then one thread should complete. The remaining
+ * thread should complete after the addition of a second object.
+ */
+ public void testBlockedRemoveWithAdd() {
+
+ Buffer blockingBuffer = BlockingBuffer.decorate(new MyBuffer());
+ Object obj = new Object();
+
+ // run methods will remove and compare -- must wait for add
+ Thread thread1 = new ReadThread(blockingBuffer, obj, null, "remove");
+ Thread thread2 = new ReadThread(blockingBuffer, obj, null, "remove");
+ thread1.start();
+ thread2.start();
+
+ // give hungry read threads ample time to hang
+ delay();
+
+ blockingBuffer.add(obj);
+
+ // allow notified threads to complete
+ delay();
+
+ // There should be one thread waiting.
+ assertTrue ("There is one thread waiting", thread1.isAlive() ^ thread2.isAlive());
+
+ blockingBuffer.add(obj);
+
+ // allow notified thread to complete
+ delay();
+
+ // There should not be any threads waiting.
+ if(thread1.isAlive() || thread2.isAlive())
+ fail("Live thread(s) when both should be dead.");
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Tests {@link BlockingBuffer#remove()} in combination with {@link BlockingBuffer#addAll()} using multiple read threads.
+ *
+ * Two read threads should block on an empty buffer until a
+ * singleton collection is added then one thread should
+ * complete. The remaining thread should complete after the
+ * addition of a second singleton.
+ */
+ public void testBlockedRemoveWithAddAll1() {
+
+ Buffer blockingBuffer = BlockingBuffer.decorate(new MyBuffer());
+ Object obj = new Object();
+
+ // run methods will remove and compare -- must wait for addAll
+ Thread thread1 = new ReadThread(blockingBuffer, obj, null, "remove");
+ Thread thread2 = new ReadThread(blockingBuffer, obj, null, "remove");
+ thread1.start();
+ thread2.start();
+
+ // give hungry read threads ample time to hang
+ delay();
+
+ blockingBuffer.addAll(Collections.singleton(obj));
+
+ // allow notified threads to complete
+ delay();
+
+ // There should be one thread waiting.
+ assertTrue ("There is one thread waiting", thread1.isAlive() ^ thread2.isAlive());
+
+ blockingBuffer.addAll(Collections.singleton(obj));
+
+ // allow notified thread to complete
+ delay();
+
+ // There should not be any threads waiting.
+ if(thread1.isAlive() || thread2.isAlive())
+ fail("Live thread(s) when both should be dead.");
+ }
+
+
+ //-----------------------------------------------------------------------
+ /**
+ * Tests {@link BlockingBuffer#remove()} in combination with {@link BlockingBuffer#addAll()} using multiple read threads.
+ *
+ * Two read threads should block on an empty buffer until a
+ * collection with two distinct objects is added then both
+ * threads should complete. Each thread should have read a
+ * different object.
+ */
+ public void testBlockedRemoveWithAddAll2() {
+
+ Buffer blockingBuffer = BlockingBuffer.decorate(new MyBuffer());
+ Object obj1 = new Object();
+ Object obj2 = new Object();
+
+ Set objs = Collections.synchronizedSet(new HashSet());
+ objs.add(obj1);
+ objs.add(obj2);
+
+ // run methods will remove and compare -- must wait for addAll
+ Thread thread1 = new ReadThread(blockingBuffer, objs, "remove");
+ Thread thread2 = new ReadThread(blockingBuffer, objs, "remove");
+ thread1.start();
+ thread2.start();
+
+ // give hungry read threads ample time to hang
+ delay();
+
+ blockingBuffer.addAll(objs);
+
+ // allow notified threads to complete
+ delay();
+
+ assertEquals("Both objects were removed", 0, objs.size());
+
+ // There should not be any threads waiting.
+ if(thread1.isAlive() || thread2.isAlive())
+ fail("Live thread(s) when both should be dead.");
+ }
+
+ //-----------------------------------------------------------------------
/**
* Tests interrupted remove.
*/
@@ -305,15 +394,13 @@
thread.interrupt();
// Chill, so thread can throw and add message to exceptionList
- try {
- Thread.currentThread().sleep(100);
- } catch (InterruptedException e) {}
+ delay();
assertTrue("Thread interrupt should have led to underflow",
exceptionList.contains("BufferUnderFlow"));
if (thread.isAlive()) {
- fail("Hung read thread");
+ fail("Read thread has hung.");
}
}
@@ -370,6 +457,7 @@
Object obj;
ArrayList exceptionList = null;
String action = "get";
+ Set objs;
ReadThread (Buffer buffer, Object obj) {
super();
@@ -392,12 +480,22 @@
this.action = action;
}
+ ReadThread (Buffer buffer, Set objs, String action) {
+ super();
+ this.buffer = buffer;
+ this.objs = objs;
+ this.action = action;
+ }
+
public void run() {
try {
if (action == "get") {
assertSame(obj, buffer.get());
} else {
- assertSame(obj, buffer.remove());
+ if (null != obj)
+ assertSame(obj, buffer.remove());
+ else
+ assertTrue(objs.remove(buffer.remove()));
}
} catch (BufferUnderflowException ex) {
exceptionList.add("BufferUnderFlow");
@@ -419,5 +517,11 @@
throw new BufferUnderflowException();
return remove(0);
}
+ }
+
+ private void delay(){
+ try {
+ Thread.currentThread().sleep(100);
+ } catch (InterruptedException e) {}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org