org.j4me.collections.CubbyHole.java Source code

Java tutorial

Introduction

Here is the source code for org.j4me.collections.CubbyHole.java

Source

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