Java tutorial
//package org.j4me.collections; /** * Stores a single object for the producer/consumer pattern and takes care * of thread synchronization. A first thread, the producer, can put an object * into the cubby hole using <code>set</code>. If there already is an object * in the cubby hole then it is discarded. Meanwhile a second thread, the * consumer, can get the object using <code>get</code>. If no object is in * the cubby hole the consumer will block until one is available. * <p> * <code>CubbyHole</code> is valuable for several situations including where * a lot of information is produced and consumption is time consuming. For * example an application that does expensive rendering based on location * events could only render based on the very latest location. */ public class CubbyHole { /** * The object stored by the producer. If this is <code>null</code> * there is nothing to consume. */ private Object cubby; /** * Called by the producer to put <code>data</code> into the cubby hole. * If there was another object stored in the cubby hole it will be * removed and returned. * <p> * This is a thread-safe method that returns immediately. If another * thread, acting as the consumer, is blocking on <code>get</code> it * will start running so long as <code>data</code> is not <code>null</code>. * * @param data is the information to store in the cubby hole. If * <code>null</code> then there is no job and any calls to <code>get</code> * will block until <code>set</code> is called again with a non- * <code>null</code> object. * @return The object in the cubby hole replaced by <code>data</code> * or <code>null</code> if nothing was stored. */ public synchronized Object set (Object data) { Object ret = cubby; cubby = data; // Unblock a consumer waiting on get(). notifyAll(); return ret; } /** * Called by the consumer to get an object stored in the cubby hole. * If nothing is stored this thread will block until <code>set</code> * is called by a different thread. * * @return The object stored in the cubby hole by a call to <code>set</code>. * This will never return <code>null</code>. * @throws InterruptedException if the program is exiting. */ public synchronized Object get () throws InterruptedException { // Block until a job is available. while ( cubby == null ) { wait(); // Releases the lock on this when waiting and re-acquires when awaken } // Get the data in the cubby hole. Object ret = cubby; cubby = null; return ret; } /** * Looks at the cubby hole without removing the object from it. This * is a non-blocking method. * * @return The object in the cubby hole which will be <code>null</code> * if nothing is being stored. */ public synchronized Object peek () { return cubby; } /** * Test is the cubby hole is empty. This is a non-blocking method. * * @return <code>true</code> if nothing is in the cubby hole or <code> * false</code> if it has an object. */ public synchronized boolean empty () { return (cubby == null); } }---------------package org.j4me.collections; import org.j4me.*; import j2meunit.framework.*; /** * Tests the <code>CubbyHole</code> class. It is a thread synchronization * helper that stores exactly one object. A worker thread can get the very * latest information stored by a producer. * * @see org.j4me.collections.CubbyHole */ public class CubbyHoleTest extends J4METestCase { public CubbyHoleTest() { super(); } public CubbyHoleTest(String name, TestMethod method) { super(name, method); } public Test suite() { TestSuite suite = new TestSuite(); suite.addTest(new CubbyHoleTest("testBasics", new TestMethod() { public void run(TestCase tc) { ((CubbyHoleTest) tc).testBasics(); } })); suite.addTest(new CubbyHoleTest("testBlocking", new TestMethod() { public void run(TestCase tc) { ((CubbyHoleTest) tc).testBlocking(); } })); return suite; } /** * Tests that a cubby hole stores exactly one object. Thread synchronization * is not covered by this test case. */ public void testBasics() { try { CubbyHole cubby = new CubbyHole(); // Very there is nothing in the empty cubby hole. boolean isEmpty = cubby.empty(); assertTrue("The cubby hole is empty.", isEmpty); Object peek = cubby.peek(); assertNull("Nothing comes from peaking into an empty cubby hole.", peek); // Put something into the cubby hole. Integer i = new Integer(13); cubby.set(i); isEmpty = cubby.empty(); assertFalse("The cubby hole has something in it.", isEmpty); peek = cubby.peek(); assertSame("The cubby hole correctly stored our object.", i, peek); Object get = cubby.get(); assertSame("Got the object stored in the cubby.", i, get); // The cubby hole should once again be empty. isEmpty = cubby.empty(); assertTrue("The cubby hole is empty again.", isEmpty); peek = cubby.peek(); assertNull("Nothing comes from peaking into the empty again cubby hole.", peek); // Put several objects into the cubby hole before taking one out. Integer i1 = new Integer(1); Integer i2 = new Integer(2); Integer i3 = new Integer(3); get = cubby.set(i1); assertNull("Nothing returned from empty cubby hole.", get); get = cubby.set(i2); assertSame("Old data i1 returned from cubby hole.", i1, get); get = cubby.set(i3); assertSame("Old data i2 returned from cubby hole.", i2, get); get = cubby.get(); assertSame("Newest data is in cubby hole.", i3, get); } catch (InterruptedException e) { fail(e.toString()); } } /** * Tests that a consumer thread blocks waiting for a producer to add * something to the cubby hole. */ public void testBlocking() { final CubbyHole one = new CubbyHole(); final CubbyHole two = new CubbyHole(); class Consumer extends Thread { public void run() { try { // Block waiting for something in the first cubby hole. Object consume = one.get(); // The producer thread should be blocking waiting for // this thread to put something into the second cubby hole. two.set(consume); } catch (Throwable t) { fail(t.toString()); } } } try { // Create a consumer thread. Consumer consumer = new Consumer(); consumer.start(); // Give up the CPU to let the consumer start and block. Thread.sleep(0); // Put some data into the first cubby hole to unblock the consumer. Integer data = new Integer(13); one.set(data); // Get data from the second cubby hole. This thread will block // until the consumer puts something into it. Integer result = (Integer) two.get(); // Verify the consumer thread read our original data from the // first cubby hole and put it into the second. assertSame("Data integrety verified.", data, result); } catch (InterruptedException e) { fail(e.toString()); } } }