Mega Code Archive

 
Categories / Java / Threads
 

Stores a single object for the producerconsumer pattern and takes care of thread synchronization

//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() );     }   } }